bitforskydningerne betragtes undertiden som bitvise operationer, fordi de behandler en værdi som en række bit snarere end som en numerisk størrelse. I disse operationer flyttes cifrene eller forskydes til venstre eller højre. Registre i en computerprocessor har en fast bredde, så nogle bits vil blive “forskudt” af registret i den ene ende, mens det samme antal bits “forskydes” fra den anden ende; forskellene mellem bitskiftoperatører ligger i, hvordan de bestemmer værdierne for de forskudte bits.
Bit adresseredit
hvis bredden af registret (ofte 32 eller endda 64) er større end antallet af bits (normalt 8) af den mindste adresserbare enhed (atomelement), ofte kaldet byte, inducerer skiftoperationerne et adresseringssystem på bitene.Ser man bort fra grænseeffekterne i begge ender af registret, aritmetiske og logiske skiftoperationer opfører sig ens, og et skift med 8 bitpositioner transporterer bitmønsteret med 1 byte-position på følgende måde:
|
et venstre skift med 8 positioner øger byte-adressen med 1 |
|
et højre skift med 8 positioner reducerer byte-adressen med 1 |
|
et venstre skift med 8 positioner reducerer byte-adressen med 1 |
|
et højre skift med 8 positioner øger byte-adressen med 1 |
aritmetisk skiftredit
i et aritmetisk skift kasseres de bits, der forskydes ud af begge ender. I et venstre aritmetisk skift, nuller skiftes ind til højre; i et højre aritmetisk skift forskydes tegnbiten (MSB i to komplement) til venstre og bevarer således operandens tegn.
dette eksempel bruger et 8-bit register, fortolket som to komplement:
00010111 (decimal +23) LEFT-SHIFT= 00101110 (decimal +46)
10010111 (decimal −105) RIGHT-SHIFT= 11001011 (decimal −53)
i det første tilfælde blev det venstre ciffer forskudt forbi slutningen af registret, og en ny 0 blev flyttet til den højeste position. I det andet tilfælde blev den højeste 1 flyttet ud (måske ind i bæreflagget), og en ny 1 blev kopieret til den yderste venstre position og bevarede tegnet på nummeret. Flere skift forkortes undertiden til et enkelt skift med et antal cifre. For eksempel:
00010111 (decimal +23) LEFT-SHIFT-BY-TWO= 01011100 (decimal +92)
et venstre aritmetisk skift med n svarer til at multiplicere med 2n (forudsat at værdien ikke løber over), mens et højre aritmetisk skift med n af en tos komplementværdi svarer til at dividere med 2n og afrunding mod negativ uendelighed. Hvis det binære tal behandles som et komplement, resulterer den samme højre skiftoperation i division med 2n og afrunding mod nul.
logisk skiftrediger
venstre logisk skift
|
højre logisk skift
|
i et logisk skift skiftes nuller ind for at erstatte de kasserede bits. Derfor er de logiske og aritmetiske venstre-skift nøjagtigt de samme.
da det logiske højre skift indsætter værdi 0 bit i den mest betydningsfulde bit, i stedet for at kopiere tegnbit, er det ideelt til usignerede binære tal, mens det aritmetiske højre skift er ideelt til signerede to ‘ s komplementære binære tal.
cirkulært skiftredit
en anden form for skift er cirkulært skift, bitvis rotation eller bitrotation.
Rotaterediger
venstre cirkulært skift eller roter
|
højre cirkulært skift eller roter
|
i denne operation, undertiden kaldet Roter ingen bære, bitene “roteres” som om venstre og højre ende af registret blev sammenføjet. Den værdi, der forskydes til højre under et venstre-skift, er den værdi, der blev forskudt til venstre, og omvendt for en højre-skift-operation. Dette er nyttigt, hvis det er nødvendigt at bevare alle de eksisterende bits, og bruges ofte i digital kryptografi.
Roter gennem carryEdit
venstre rotere gennem bære
|
højre drej gennem bære
|
Rotate through carry er en variant af rotationsoperationen, hvor den bit, der forskydes i (i begge ender) er den gamle værdi af bæreflagget, og den bit, der forskydes (i den anden ende) bliver den nye værdi af bæreflagget.
en enkelt rotation gennem bære kan simulere et logisk eller aritmetisk skift af en position ved at indstille bæreflagget på forhånd. For eksempel, hvis bæreflagget indeholder 0, er x RIGHT-ROTATE-THROUGH-CARRY-BY-ONE
et logisk højre-skift, og hvis bæreflagget indeholder en kopi af tegnbiten, er x RIGHT-ROTATE-THROUGH-CARRY-BY-ONE
et aritmetisk højre-skift. Af denne grund har nogle mikrocontrollere som lave ende billeder bare rotere og rotere gennem bære, og gider ikke med aritmetiske eller logiske skiftinstruktioner.
Rotate through carry er især nyttigt, når der udføres skift på tal større end processorens oprindelige ordstørrelse, fordi hvis et stort antal er gemt i to registre, skal den bit, der forskydes fra den ene ende af det første register, komme ind i den anden ende af det andet. Med rotate-through-carry er den bit “gemt” i bæreflagget under det første skift, klar til at skifte ind under det andet skift uden ekstra forberedelse.
på højt niveau sprogRediger
C-familyEdit
på C-familiesprog er de logiske skiftoperatører “<<
” for Venstre Skift og “>>
” for højre skift. Antallet af steder at skifte er givet som det andet argument til operatøren. For eksempel,
x = y << 2;
tildeler x
resultatet af at skifte y
til venstre med to bits, hvilket svarer til en multiplikation med fire.
skift kan resultere i implementeringsdefineret adfærd eller udefineret adfærd, så man skal være forsigtig, når man bruger dem. Resultatet af at skifte med en bit tæller større end eller lig med ordets størrelse er udefineret adfærd i C og C++. Højreskift en negativ værdi er implementeringsdefineret og anbefales ikke af god kodningspraksis; resultatet af venstreskift af en signeret værdi er udefineret, hvis resultatet ikke kan repræsenteres i resultattypen.
i C# er højre skift et aritmetisk skift, når den første operand er en int eller lang. Hvis den første operand er af typen uint eller ulong, er højre skift et logisk skift.
cirkulære skiftredit
C-familien af sprog mangler en rotationsoperator, men man kan syntetiseres fra skiftoperatørerne. Der skal udvises forsigtighed for at sikre, at erklæringen er velformet for at undgå udefineret adfærd og timingangreb i programmer med sikkerhedskrav. For eksempel roterer en naiv implementering, der Venstre, en 32-bit usigneret værdi x
ved n
positioner er simpelthen:
uint32_t x = ..., n = ...;uint32_t y = (x << n) | (x >> (32 - n));
et skift med 0
bits resulterer imidlertid i udefineret opførsel i højre udtryk (x >> (32 - n))
fordi 32 - 0
er 32
, og 32
er uden for området inklusive. Et andet forsøg kan resultere i:
uint32_t x = ..., n = ...;uint32_t y = n ? (x << n) | (x >> (32 - n)) : x;
hvor skiftbeløbet testes for at sikre, at det ikke introducerer udefineret adfærd. Filialen tilføjer dog en ekstra kodesti og giver mulighed for timinganalyse og angreb, hvilket ofte ikke er acceptabelt i programmer med høj integritet. Derudover kompileres koden til flere maskininstruktioner, hvilket ofte er mindre effektivt end processorens oprindelige instruktion.
for at undgå udefineret adfærd og grene under GCC og Clang anbefales følgende. Mønsteret genkendes af mange kompilatorer, og kompilatoren udsender en enkelt rotationsinstruktion:
uint32_t x = ..., n = ...;uint32_t y = (x << n) | (x >> (-n & 31));
der er også compiler-specifikke iboende, der implementerer cirkulære skift, som _rotl8, _rotl16, _rotr8, _rotr16 i Microsoft Visual C++. Clang giver nogle rotere iboende til Microsoft-Kompatibilitet, der lider af ovenstående problemer. GCC tilbyder ikke rotere iboende. Intel leverer også 86 iboende.
JavaEdit
i Java er alle heltalstyper underskrevet, så operatørerne ” <<
” og “>>
” udfører aritmetiske skift. Java tilføjer operatøren ” >>>
” for at udføre logiske højre skift, men da de logiske og aritmetiske venstre skiftoperationer er identiske for signeret heltal, er der ingen “<<<
” operatør i Java.
flere detaljer om Java shift operators:
- operatørerne
<<
(venstre skift),>>
(signeret højre skift) og>>>
(usigneret højre skift) kaldes skiftoperatører. - typen af skiftudtryk er den promoverede type af venstre operand. For eksempel
aByte >>> 2
svarer til((int) aByte) >>> 2
. - hvis den promoverede type af venstre operand er int, Bruges kun de fem laveste ordens bits i højre operand som skiftafstand. Det er som om den højre operand blev udsat for en bitvis logisk og operatør & med maskeværdien 0h1f (0b11111). Den faktisk anvendte skiftafstand er derfor altid i området 0 til 31 inklusive.
- hvis den promoverede type af venstre operand er lang, bruges kun de seks laveste ordens bits i højre operand som skiftafstand. Det er som om den højre operand blev udsat for en bitvis logisk og operatør & med maskeværdien 0h3f (0b111111). Den faktisk anvendte skiftafstand er derfor altid i området 0 til 63 inklusive.
- værdien af
n>>> s
er n højre-forskudt s bit positioner med nul-forlængelse. - i bit-og shift-operationer konverteres typen
byte
implicit tilint
. Hvis byte-værdien er negativ, er den højeste bit en, så bruges de til at fylde de ekstra bytes i int. Såbyte b1 = -5; int i = b1 / 0h0200;
vil resultere ii == -5
.
JavaScriptEdit
JavaScript bruger bitvise operationer til at evaluere hver af to eller flere enheder sted til 1 eller 0.
PascalEdit
i Pascal såvel som i alle dens dialekter (såsom Object Pascal og Standard Pascal) er de logiske venstre og højre skiftoperatører henholdsvis ” shl
” og ” shr
“. Selv for underskrevne heltal opfører shr
sig som et logisk skift og kopierer ikke tegnbiten. Antallet af steder at skifte er angivet som det andet argument. Resultatet af at skifte y til venstre med to bits:
x := y shl 2;