Bitvis och skiftoperatorer (C#-referens)
Bitvis- och skiftoperatorerna omfattar oanvänd bitvis komplement, binär vänster- och högerförskjutning, osignerat högerskift och binära logiska AND-, OR- och exklusiva OR-operatorer. Dessa operander tar operander av de integrerade numeriska typerna eller teckentypen .
- Unary
~
-operator (bitvis komplement) - Binära operatorer
<<
(vänster skift),>>
(höger skift)och>>>
(osignerat högerskift) - Binära operatorer
&
(logiska AND),|
(logiska OR) och^
(logiska exklusiva OR)- operatorer
Dessa operatorer definieras för typerna int
, uint
, long
och ulong
. När båda operanderna är av andra integraltyper (sbyte
, , short
byte
, ushort
eller char
), konverteras deras värden till int
typen, vilket också är resultattypen för en åtgärd. När operander är av olika integraltyper konverteras deras värden till den närmaste innehåller integraltyp. Mer information finns i avsnittet Numeriska kampanjer i C#-språkspecifikationen. De sammansatta operatorerna (till exempel >>=
) konverterar inte sina argument till int
eller har resultattypen som int
.
Operatorerna &
, |
och ^
definieras också för operander av typen bool
. Mer information finns i Booleska logiska operatorer.
Bitvis och skiftåtgärder orsakar aldrig spill och ger samma resultat i markerade och omarkerade kontexter.
Bitvis komplementoperator ~
Operatorn ~
genererar ett bitvis komplement av sin operand genom att vända varje bit:
uint a = 0b_0000_1111_0000_1111_0000_1111_0000_1100;
uint b = ~a;
Console.WriteLine(Convert.ToString(b, toBase: 2));
// Output:
// 11110000111100001111000011110011
Du kan också använda symbolen ~
för att deklarera finalizers. Mer information finns i Finalizers.
Vänster skiftoperator <<
Operatorn <<
flyttar sin vänstra operande till vänster efter antalet bitar som definieras av dess högra operande. Information om hur den högra operanden definierar skiftantalet finns i avsnittet Skiftantal för skiftoperatorer .
Vänsterskiftsåtgärden tar bort de högordningsbitar som ligger utanför resultattypens intervall och anger tomma bitpositioner i låg ordning till noll, vilket visas i följande exempel:
uint x = 0b_1100_1001_0000_0000_0000_0000_0001_0001;
Console.WriteLine($"Before: {Convert.ToString(x, toBase: 2)}");
uint y = x << 4;
Console.WriteLine($"After: {Convert.ToString(y, toBase: 2)}");
// Output:
// Before: 11001001000000000000000000010001
// After: 10010000000000000000000100010000
Eftersom skiftoperatorerna endast definieras för typerna int
, uint
, long
och ulong
innehåller resultatet av en åtgärd alltid minst 32 bitar. Om den vänstra operanden är av en annan integrerad typ (sbyte
, , short
byte
, ushort
eller char
), konverteras dess värde till int
typen, som följande exempel visar:
byte a = 0b_1111_0001;
var b = a << 8;
Console.WriteLine(b.GetType());
Console.WriteLine($"Shifted byte: {Convert.ToString(b, toBase: 2)}");
// Output:
// System.Int32
// Shifted byte: 1111000100000000
Högerskiftsoperator >>
Operatorn >>
flyttar sin vänstra operande till höger med antalet bitar som definieras av dess högra operande. Information om hur den högra operanden definierar skiftantalet finns i avsnittet Skiftantal för skiftoperatorer .
Åtgärden right-shift tar bort lågordningsbitarna, vilket visas i följande exempel:
uint x = 0b_1001;
Console.WriteLine($"Before: {Convert.ToString(x, toBase: 2), 4}");
uint y = x >> 2;
Console.WriteLine($"After: {Convert.ToString(y, toBase: 2).PadLeft(4, '0'), 4}");
// Output:
// Before: 1001
// After: 0010
De tomma bitpositionerna i hög ordning anges baserat på typen av den vänstra operanden enligt följande:
Om den vänstra operanden är av typen
int
ellerlong
, utför operatorn för höger skift ett aritmetiskt skift: värdet för den viktigaste biten (teckenbiten) för den vänstra operanden sprids till de tomma bitpositionerna i hög ordning. Det innebär att de tomma bitpositionerna i hög ordning är inställda på noll om den vänstra operanden inte är negativ och inställd på en om den är negativ.int a = int.MinValue; Console.WriteLine($"Before: {Convert.ToString(a, toBase: 2)}"); int b = a >> 3; Console.WriteLine($"After: {Convert.ToString(b, toBase: 2)}"); // Output: // Before: 10000000000000000000000000000000 // After: 11110000000000000000000000000000
Om den vänstra operanden är av typen
uint
ellerulong
utför operatorn right-shift ett logiskt skift: de tomma bitpositionerna i hög ordning är alltid inställda på noll.uint c = 0b_1000_0000_0000_0000_0000_0000_0000_0000; Console.WriteLine($"Before: {Convert.ToString(c, toBase: 2), 32}"); uint d = c >> 3; Console.WriteLine($"After: {Convert.ToString(d, toBase: 2).PadLeft(32, '0'), 32}"); // Output: // Before: 10000000000000000000000000000000 // After: 00010000000000000000000000000000
Kommentar
Använd den osignerade högerväxlingsoperatorn för att utföra ett logiskt skift på operander av signerade heltalstyper. Detta är att föredra för att casta en vänster operand till en osignerad typ och sedan gjuta resultatet av en skiftåtgärd tillbaka till en signerad typ.
Osignerad högerskiftsoperator >>>
Operatorn >>>
är tillgänglig i C# 11 och senare och skiftar sin vänstra operande till höger efter antalet bitar som definieras av dess högra operand. Information om hur den högra operanden definierar skiftantalet finns i avsnittet Skiftantal för skiftoperatorer .
Operatorn >>>
utför alltid ett logiskt skift. Det innebär att de tomma bitpositionerna i hög ordning alltid är inställda på noll, oavsett typ av vänster operand. Operatorn>>
utför ett aritmetiskt skift (dvs. värdet för den viktigaste biten sprids till de tomma bitpositionerna i hög ordning) om den vänstra operanden är av en signerad typ. I följande exempel visas skillnaden mellan >>
operatorerna och >>>
för en negativ vänsteroperation:
int x = -8;
Console.WriteLine($"Before: {x,11}, hex: {x,8:x}, binary: {Convert.ToString(x, toBase: 2), 32}");
int y = x >> 2;
Console.WriteLine($"After >>: {y,11}, hex: {y,8:x}, binary: {Convert.ToString(y, toBase: 2), 32}");
int z = x >>> 2;
Console.WriteLine($"After >>>: {z,11}, hex: {z,8:x}, binary: {Convert.ToString(z, toBase: 2).PadLeft(32, '0'), 32}");
// Output:
// Before: -8, hex: fffffff8, binary: 11111111111111111111111111111000
// After >>: -2, hex: fffffffe, binary: 11111111111111111111111111111110
// After >>>: 1073741822, hex: 3ffffffe, binary: 00111111111111111111111111111110
Logisk AND-operator &
Operatorn &
beräknar bitvis logiska OCH för dess integrerade operander:
uint a = 0b_1111_1000;
uint b = 0b_1001_1101;
uint c = a & b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10011000
För bool
operander beräknar operatorn &
logiska OCH för sina operander. Den unary &
operatorn är adress-of-operatorn.
Logisk exklusiv OR-operator ^
Operatorn ^
beräknar den bitvis logiska exklusiva OR, även kallad bitvis logisk XOR, för dess integrerade operander:
uint a = 0b_1111_1000;
uint b = 0b_0001_1100;
uint c = a ^ b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 11100100
För bool
operander beräknar operatorn ^
den logiska exklusiva OR för sina operander.
Logisk OR-operator |
Operatorn |
beräknar den bitvis logiska OR:en för dess integrerade operander:
uint a = 0b_1010_0000;
uint b = 0b_1001_0001;
uint c = a | b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10110001
För bool
operander beräknar operatorn |
den logiska OR :en för dess operander.
Sammansatt tilldelning
För en binär operator op
, ett sammansatt tilldelningsuttryck för formuläret
x op= y
motsvarar
x = x op y
förutom att x
endast utvärderas en gång.
I följande exempel visas användningen av sammansatt tilldelning med bitvis operatorer och skiftoperatorer:
uint INITIAL_VALUE = 0b_1111_1000;
uint a = INITIAL_VALUE;
a &= 0b_1001_1101;
Display(a); // output: 10011000
a = INITIAL_VALUE;
a |= 0b_0011_0001;
Display(a); // output: 11111001
a = INITIAL_VALUE;
a ^= 0b_1000_0000;
Display(a); // output: 01111000
a = INITIAL_VALUE;
a <<= 2;
Display(a); // output: 1111100000
a = INITIAL_VALUE;
a >>= 4;
Display(a); // output: 00001111
a = INITIAL_VALUE;
a >>>= 4;
Display(a); // output: 00001111
void Display(uint x) => Console.WriteLine($"{Convert.ToString(x, toBase: 2).PadLeft(8, '0'), 8}");
På grund av numeriska kampanjer kanske resultatet av op
åtgärden inte implicit kan konverteras till typen T
x
. I ett sådant fall, om op
är en fördefinierad operator och resultatet av åtgärden uttryckligen kan konverteras till typen T
av x
, är ett sammansatt tilldelningsuttryck av formuläret x op= y
likvärdigt med x = (T)(x op y)
, förutom att endast x
utvärderas en gång. Följande exempel visar det beteendet:
byte x = 0b_1111_0001;
int b = x << 8;
Console.WriteLine($"{Convert.ToString(b, toBase: 2)}"); // output: 1111000100000000
x <<= 8;
Console.WriteLine(x); // output: 0
Prioritet för operator
Följande lista beställer bitvis och skiftoperatorer från den högsta prioriteten till den lägsta:
- Bitvis komplementoperator
~
- Skiftoperatorer
<<
,>>
och>>>
- Logisk AND-operator
&
- Logisk exklusiv OR-operator
^
- Logisk OR-operator
|
Använd parenteser, ()
, för att ändra ordningen på utvärderingen som har införts av operatorprioriteten:
uint a = 0b_1101;
uint b = 0b_1001;
uint c = 0b_1010;
uint d1 = a | b & c;
Display(d1); // output: 1101
uint d2 = (a | b) & c;
Display(d2); // output: 1000
void Display(uint x) => Console.WriteLine($"{Convert.ToString(x, toBase: 2), 4}");
En fullständig lista över C#-operatorer ordnade efter prioritetsnivå finns i avsnittet Operatorprioriteten i artikeln C#-operatorer .
Skiftantal för skiftoperatorerna
För uttrycken x << count
, x >> count
och x >>> count
beror det faktiska skiftantalet på typen av x
på följande sätt:
Om typen av är eller definieras skiftantalet av fem bitar i den högra operanden med låg ordning.
uint
int
x
Det vill: skiftantalet beräknas fråncount & 0x1F
(ellercount & 0b_1_1111
).Om typen av
x
ärlong
ellerulong
definieras skiftantalet av den låga ordningen sex bitar av den högra operanden. Det vill: skiftantalet beräknas fråncount & 0x3F
(ellercount & 0b_11_1111
).
Följande exempel visar det beteendet:
int count1 = 0b_0000_0001;
int count2 = 0b_1110_0001;
int a = 0b_0001;
Console.WriteLine($"{a} << {count1} is {a << count1}; {a} << {count2} is {a << count2}");
// Output:
// 1 << 1 is 2; 1 << 225 is 2
int b = 0b_0100;
Console.WriteLine($"{b} >> {count1} is {b >> count1}; {b} >> {count2} is {b >> count2}");
// Output:
// 4 >> 1 is 2; 4 >> 225 is 2
int count = -31;
int c = 0b_0001;
Console.WriteLine($"{c} << {count} is {c << count}");
// Output:
// 1 << -31 is 2
Kommentar
Som föregående exempel visar kan resultatet av en skiftåtgärd vara icke-noll även om värdet för den högra operanden är större än antalet bitar i den vänstra operanden.
Logiska uppräkningsoperatorer
Operatorerna , , och ^
stöds också av alla uppräkningstyper. |
&
~
För operander av samma uppräkningstyp utförs en logisk åtgärd på motsvarande värden för den underliggande integraltypen. För alla x
och y
av en uppräkningstyp T
med en underliggande typ U
x & y
ger uttrycket till exempel samma resultat som (T)((U)x & (U)y)
uttrycket.
Du använder vanligtvis bitvis logiska operatorer med en uppräkningstyp som definieras med attributet Flaggor . Mer information finns i avsnittet Uppräkningstyper som bitflaggor i artikeln Uppräkningstyper .
Överlagring av operator
En användardefinierad typ kan överbelasta operatorerna ~
, <<
, >>
, >>>
, &
, |
och ^
. När en binär operator är överbelastad överbelastas även motsvarande sammansatta tilldelningsoperator implicit. En användardefinierad typ kan inte uttryckligen överbelasta en sammansatt tilldelningsoperator.
Om en användardefinierad typ T
överbelastar operatorn <<
, >>
eller >>>
måste typen av den vänstra operanden vara T
. I C# 10 och tidigare måste typen av den högra operanden vara int
. Från och med C# 11 kan typen av den högra operanden för en överbelastad skiftoperator vara valfri.
Språkspecifikation för C#
Mer information finns i följande avsnitt i C#-språkspecifikationen:
- Bitvis komplementoperator
- Skiftoperatorer
- Logiska operatorer
- Sammansatt tilldelning
- Numeriska kampanjer
- C# 11 – Avslappnade skiftkrav
- C# 11 – Logisk högerväxlingsoperator