Bitenkénti és shift operátorok (C#-referencia)
A bitenkénti és a shift operátorok közé tartoznak a nem bitenkénti kiegészítések, a bináris bal és jobb eltolás, az aláíratlan jobb eltolás, valamint a bináris logikai ÉS, OR és kizárólagos VAGY operátorok. Ezek az operandusok az integrál numerikus típusok vagy a karaktertípus operandusait veszik fel.
- Unary
~
(bitenkénti kiegészítés) operátor - Bináris
<<
(bal shift),>>
(jobb shift), és>>>
(nem aláírt jobb műszak) operátorok - Bináris
&
(logikai ÉS),|
(logikai VAGY) és^
(logikai kizáró VAGY) operátorok
Ezek az operátorok a int
, uint
, long
és ulong
típusokhoz vannak definiálva. Ha mindkét operandus más integrál típusú (sbyte
, , , short
vagy char
ushort
) típusú, byte
akkor az értékek a int
típusra lesznek konvertálva, ami szintén egy művelet eredménytípusa. Ha az operandusok különböző integráltípusok, az értékek a legközelebbi integrált típusra lesznek konvertálva. További információkért tekintse meg a C#-nyelv specifikációjának Numerikus promóciók szakaszát. Az összetett operátorok (például >>=
) nem konvertálják az argumentumaikat int
az eredménytípusra, vagy az eredmény típusa a következő int
.
A &
, |
és ^
operátorok is definiálva vannak a bool
típus operandusaihoz. További információ: Logikai operátorok.
A bitenkénti és a váltási műveletek soha nem okoznak túlcsordulást, és ugyanazokat az eredményeket eredményezik a ellenőrzött és a nem ellenőrzött környezetekben.
Bitenkénti komplementer operátor ~
Az ~
operátor az operandus bitenkénti kiegészítését állítja elő az egyes bitek megfordításával:
uint a = 0b_0000_1111_0000_1111_0000_1111_0000_1100;
uint b = ~a;
Console.WriteLine(Convert.ToString(b, toBase: 2));
// Output:
// 11110000111100001111000011110011
A szimbólummal ~
véglegesítőket is deklarálhat. További információ: Finalizers.
Bal shift operátor <<
Az <<
operátor a bal oldali operandusát balra tolja a jobb oldali operandus által meghatározott bitek számával. Arról, hogy a jobb oldali operandus hogyan határozza meg a műszakszámot, tekintse meg a shift operátorok szakaszának Shift count (Műszakok száma) szakaszát.
A bal oldali eltolásos művelet elveti az eredménytípus tartományán kívül eső nagy értékű biteket, és nullára állítja az alacsony sorrendű üres bitpozíciókat, ahogy az alábbi példa mutatja:
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
Mivel a shift operátorok csak a int
, uint
, long
és ulong
a típusok esetében vannak definiálva, a művelet eredménye mindig legalább 32 bitet tartalmaz. Ha a bal oldali operandus egy másik integráltípusú (sbyte
, byte
, , short
vagy char
ushort
), akkor az értéke a típusra int
lesz konvertálva, ahogyan az alábbi példa mutatja:
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
Jobb műszakos operátor >>
Az >>
operátor a jobb oldali operandus által meghatározott bitek számával jobbra tolja el a bal oldali operandusát. Arról, hogy a jobb oldali operandus hogyan határozza meg a műszakszámot, tekintse meg a shift operátorok szakaszának Shift count (Műszakok száma) szakaszát.
A jobb oldali shift művelet elveti az alacsony sorrendű biteket, ahogy az alábbi példa is mutatja:
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
A magas sorrendű üres bitpozíciók a bal oldali operandus típusától függően vannak beállítva az alábbiak szerint:
Ha a bal oldali operandus típusa
int
vagylong
, akkor a jobb műszak operátora aritmetikai eltolást hajt végre: a bal oldali operandus legjelentősebb bitjének (jelbitjének) értékét propagálja a rendszer a nagy sorrendű üres bitpozíciókba. Ez azt jelenti, hogy a magas sorrendű üres bitpozíciók nullára vannak állítva, ha a bal oldali operandus nem negatív, és negatív értékre van állítva.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
Ha a bal oldali operandus típusú
uint
, vagyulong
ha a jobb oldali shift operátor logikai eltolást hajt végre: a nagy sorrendű üres bitpozíciók mindig nullára vannak állítva.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
Feljegyzés
Az aláíratlan jobb shift operátorral logikai műszakot hajthat végre aláírt egész szám típusú operandusokon. Ez előnyben részesíti a bal oldali operandus hozzárendelés nélküli típusra történő átírását, majd a shift művelet eredményét egy aláírt típusra.
Nem aláírt jobb műszakos operátor >>>
A C# 11-es és újabb verzióiban elérhető operátor a >>>
jobb oldali operandus által meghatározott bitek számával jobbra tolja el a bal oldali operandusát. Arról, hogy a jobb oldali operandus hogyan határozza meg a műszakszámot, tekintse meg a shift operátorok szakaszának Shift count (Műszakok száma) szakaszát.
Az >>>
operátor mindig logikai eltolódást hajt végre. Ez azt jelenti, hogy a magas sorrendű üres bitpozíciók mindig nullára vannak állítva, függetlenül a bal oldali operandus típusától. Az >>
operátor aritmetikai eltolódást hajt végre (azaz a legjelentősebb bit értékét propagálja a rendszer a nagy sorrendű üres bitpozíciókba), ha a bal oldali operandus aláírt típusú. Az alábbi példa a negatív bal oldali operandus és >>>
operátorok közötti >>
különbséget mutatja be:
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
Logikai ÉS operátor >
Az &
operátor kiszámítja a bitenkénti logikai ÉS annak integrál operandusait:
uint a = 0b_1111_1000;
uint b = 0b_1001_1101;
uint c = a & b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10011000
Az operandusok esetében bool
az operátor kiszámítja &
az operandusok logikai ÉS operandusait. Az unary &
operátor az operátor címe.
Logikai kizárólagos VAGY operátor ^
Az ^
operátor kiszámítja az integrál operandusainak bitenkénti logikai kizárólagos vagy más néven bitenkénti logikai XOR-ját:
uint a = 0b_1111_1000;
uint b = 0b_0001_1100;
uint c = a ^ b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 11100100
Az operandusok esetében bool
az operátor kiszámítja ^
az operandusok logikai kizárólagosságát vagy operandusait.
Logikai VAGY operátor |
Az |
operátor kiszámítja a bitenkénti logikai VAGY annak integrál operandusait:
uint a = 0b_1010_0000;
uint b = 0b_1001_0001;
uint c = a | b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10110001
Operandusok esetén bool
az operátor kiszámítja |
az operandusok logikai VAGY operandusait.
Összetett hozzárendelés
Bináris operátor op
esetén az űrlap összetett hozzárendelési kifejezése
x op= y
egyenértékű a
x = x op y
kivéve, hogy csak x
egyszer van kiértékelve.
Az alábbi példa az összetett hozzárendelés bitenkénti és shift operátorokkal való használatát mutatja be:
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}");
Numerikus előléptetések miatt előfordulhat, hogy a op
művelet eredménye implicit módon nem konvertálható a típusra T
x
. Ilyen esetben, ha op
egy előre definiált operátor, és a művelet eredménye explicit módon átalakítható a típusrax
T
, az űrlap x op= y
összetett hozzárendelési kifejezése egyenértékűx = (T)(x op y)
, kivéve, ha x
csak egyszer lesz kiértékelve. Az alábbi példa ezt a viselkedést mutatja be:
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
Operátorok műveleti sorrendje
Az alábbi lista bitenkénti sorrendbe sorolja a operátorokat, és a legmagasabb prioritástól a legalacsonyabbig vált:
- Bitenkénti komplementer operátor
~
- Shift operátorok
<<
,>>
és>>>
- Logikai ÉS operátor
&
- Logikai kizárólagos VAGY operátor
^
- Logikai VAGY operátor
|
Zárójelek ()
használatával módosítsa az operátorok elsőbbsége által előírt kiértékelési sorrendet:
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}");
A C#-operátorok elsőbbségi szint szerint rendezett teljes listájáért tekintse meg a C# operátorok cikkének Operátorok elsőbbsége című szakaszát.
A műszak operátorainak műszakszáma
A beépített shift operátorok <<
>>
>>>
esetében a jobb oldali operandus típusának vagy olyan típusnak kell lennieint
, amely előre definiált implicit numerikus átalakítássalint
rendelkezik.
A x << count
, x >> count
és x >>> count
kifejezések esetében a tényleges műszakszám az alábbi típustól x
függ:
Ha a típus
x
vagyint
uint
az, a műszakok számát a jobb oldali operandus alacsony sorrendű öt bitje határozza meg. Ez azt jelent, hogy a műszakok száma (vagycount & 0b_1_1111
) alapjáncount & 0x1F
lesz kiszámítva.Ha a típus
x
vagylong
ulong
az, akkor a műszakok számát a jobb oldali operandus alacsonyrendű hat bitje határozza meg. Ez azt jelent, hogy a műszakok száma (vagycount & 0b_11_1111
) alapjáncount & 0x3F
lesz kiszámítva.
Az alábbi példa ezt a viselkedést mutatja be:
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
Feljegyzés
Ahogy az előző példa is mutatja, a műszakművelet eredménye nem lehet nulla akkor is, ha a jobb oldali operandus értéke nagyobb, mint a bal oldali operandus bitjeinek száma.
Logikai operátorok számbavétele
A ~
, &
, |
és ^
operátorokat bármely enumerálási típus is támogatja. Az azonos enumerálási típusú operandusok esetében a rendszer logikai műveletet hajt végre az alapul szolgáló integráltípus megfelelő értékein. Például egy mögöttes típusú U
enumerálási típus T
esetén y
x
a x & y
kifejezés ugyanazt az eredményt adja, mint a (T)((U)x & (U)y)
kifejezés.
Általában bitenkénti logikai operátorokat használ a Flags attribútummal definiált enumerálási típussal. További információkért tekintse meg az Enumerálási típusok az Enumerálástípusok cikk bitjelölők szakaszát.
Operátorok túlterhelése
A felhasználó által definiált típus túlterhelheti a ~
, <<
, >>
, >>>
, &
, |
és ^
operátorokat. Ha egy bináris operátor túlterhelt, a megfelelő összetett hozzárendelési operátor is implicit módon túlterhelt. A felhasználó által definiált típus nem tudja explicit módon túlterhelni az összetett hozzárendelési operátorokat.
Ha egy felhasználó által definiált típus T
túlterheli a <<
, >>
vagy >>>
operátort, a bal oldali operandus típusának kell lennie T
. A C# 10-es és korábbi verzióiban a jobb oldali operandus típusának kell lennie int
; a C# 11-től kezdődően a túlterhelt műszak operátorának jobb operandusának típusa bármelyik lehet.
C# nyelvspecifikáció
További információt a C# nyelvspecifikációjának alábbi szakaszaiban talál:
- Bitenkénti komplementer operátor
- Shift operátorok
- Logikai operátorok
- Összetett hozzárendelés
- Numerikus promóciók
- C# 11 – Nyugodt műszakra vonatkozó követelmények
- C# 11 – Logikai jobb műszakos operátor
Lásd még
Visszajelzés
https://aka.ms/ContentUserFeedback.
Hamarosan elérhető: 2024-ben fokozatosan kivezetjük a GitHub-problémákat a tartalom visszajelzési mechanizmusaként, és lecseréljük egy új visszajelzési rendszerre. További információ:Visszajelzés küldése és megtekintése a következőhöz: