Bit düzeyinde ve shift işleçleri (C# başvurusu)
Bit düzeyinde ve vardiya işleçleri bit düzeyinde tamamlama, ikili sol ve sağ kaydırma, işaretsiz sağ kaydırma ve ikili mantıksal AND, OR ve özel OR işleçlerini içerir. Bu işlenenler, integral sayısal türlerinin veya karakter türünün işlenenlerini alır.
- Tekli
~
(bit düzeyinde tamamlama) işleci - İkili
<<
(sol shift),>>
(sağ shift)ve>>>
(işaretsiz sağ shift) işleçleri - İkili
&
(mantıksal AND),|
(mantıksal OR) ve^
(mantıksal özel OR) işleçleri
Bu işleçler , uint
, long
ve ulong
türleri için int
tanımlanır. her iki işlenen de diğer tam sayı türlerinden (sbyte
, byte
, short
, ushort
veya char
) olduğunda, değerleri türüne int
dönüştürülür ve bu da bir işlemin sonuç türüdür. İşlenenler farklı integral türlerinde olduğunda, değerleri en yakın tam sayı türüne dönüştürülür. Daha fazla bilgi için C# dil belirtiminin Sayısal yükseltmeler bölümüne bakın. Bileşik işleçler (örneğin >>=
), bağımsız değişkenlerini int
olarak dönüştürmez veya sonuç türüne int
sahip değildir.
&
, |
ve ^
işleçleri de türün bool
işlenenleri için tanımlanır. Daha fazla bilgi için bkz . Boole mantıksal işleçleri.
Bit düzeyinde ve kaydırma işlemleri hiçbir zaman taşmaya neden olmaz ve aynı sonuçları işaretli ve işaretsiz bağlamlarda üretir.
Bit düzeyinde tamamlayıcı işleci ~
~
işleci, her biti tersine döndürerek işleneninin bit düzeyinde tamamlayıcısını oluşturur:
uint a = 0b_0000_1111_0000_1111_0000_1111_0000_1100;
uint b = ~a;
Console.WriteLine(Convert.ToString(b, toBase: 2));
// Output:
// 11110000111100001111000011110011
Sonlandırıcıları bildirmek için simgeyi ~
de kullanabilirsiniz. Daha fazla bilgi için bkz . Sonlandırıcılar.
Sol shift işleci <<
<<
işleci, soldaki işlenenini sağ işleneni tarafından tanımlanan bit sayısına göre sola kaydırıyor. Sağ işlenenin vardiya sayısını nasıl tanımladığı hakkında bilgi için shift işleçlerinin Shift sayısı bölümüne bakın.
Sol kaydırma işlemi, sonuç türü aralığının dışındaki yüksek sıralı bitleri atar ve aşağıdaki örnekte gösterildiği gibi düşük sıralı boş bit konumlarını sıfır olarak ayarlar:
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
Vardiya işleçleri yalnızca , uint
, long
ve ulong
türleri için int
tanımlandığından, işlemin sonucu her zaman en az 32 bit içerir. Sol işlenen başka bir tamsayıyı türündeyse (sbyte
, byte
, short
, ushort
veya char
), aşağıdaki örnekte gösterildiği gibi değeri türe int
dönüştürülür:
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
Right-shift işleci >>
işleci >>
, sol işlenenini sağ işleneni tarafından tanımlanan bit sayısına göre sağa kaydırıyor. Sağ işlenenin vardiya sayısını nasıl tanımladığı hakkında bilgi için shift işleçlerinin Shift sayısı bölümüne bakın.
Aşağıdaki örnekte gösterildiği gibi, right-shift işlemi düşük sıralı bitleri atar:
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
Yüksek sıralı boş bit konumları, sol işlenenin türüne göre aşağıdaki gibi ayarlanır:
Sol işlenen veya türündeyse
int
, sağ kaydırma işleci aritmetik bir kaydırma gerçekleştirir: sol işlenenin en önemli bitinin (işaret biti) değeri yüksek sıralı boş bit konumlarınalong
yayılır. Başka bir ifadeyle, sol işlenen negatif değilse yüksek sıralı boş bit konumları sıfıra ayarlanır ve negatifse bir olarak ayarlanır.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
Sol işlenen veya türündeyse
uint
, sağ kaydırma işleci mantıksal bir kaydırma gerçekleştirir: yüksek sıralı boş bit konumları her zaman sıfır olarakulong
ayarlanır.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
Not
İmzalı tamsayı türlerinin işlenenlerinde mantıksal bir kaydırma gerçekleştirmek için işaretsiz sağ kaydırma işlecini kullanın. Bu, soldaki işleneni imzasız bir türe atama ve ardından shift işleminin sonucunu imzalı bir türe geri döndürmek için tercih edilir.
İmzasız sağ shift işleci >>>
C# 11 ve sonraki sürümlerde kullanılabilen işleç, >>>
soldaki işlenenini sağ işleneni tarafından tanımlanan bit sayısına göre sağa kaydırıyor. Sağ işlenenin vardiya sayısını nasıl tanımladığı hakkında bilgi için shift işleçlerinin Shift sayısı bölümüne bakın.
işleci >>>
her zaman mantıksal bir kaydırma gerçekleştirir. Başka bir ifadeyle, sol işlenenin türü ne olursa olsun, yüksek sıralı boş bit konumları her zaman sıfır olarak ayarlanır. İşleç>>
, soldaki işlenen imzalı bir türdeyse aritmetik bir kaydırma (yani en önemli bitin değeri yüksek sıralı boş bit konumlarına yayılır) gerçekleştirir. Aşağıdaki örnekte, soldaki negatif işlenen için ve >>>
işleçleri arasındaki >>
fark gösterilmektedir:
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
Mantıksal AND işleci &
işleci, &
integral işlenenlerinin bit düzeyinde mantıksal AND değerini hesaplar:
uint a = 0b_1111_1000;
uint b = 0b_1001_1101;
uint c = a & b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10011000
İşlenenler için bool
işleç işlenenlerinin &
mantıksal VE değerlerini hesaplar. Birli &
işleç, işlecin adresidir.
Mantıksal özel OR işleci ^
^
işleci, integral işlenenlerinin bit düzeyinde mantıksal XOR olarak da bilinen bit düzeyinde mantıksal özel OR değerini hesaplar:
uint a = 0b_1111_1000;
uint b = 0b_0001_1100;
uint c = a ^ b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 11100100
İşlenenler için bool
işleç, ^
işlenenlerinin mantıksal özel OR değerini hesaplar.
Mantıksal OR işleci |
işleci, |
integral işlenenlerinin bit düzeyinde mantıksal OR değerini hesaplar:
uint a = 0b_1010_0000;
uint b = 0b_1001_0001;
uint c = a | b;
Console.WriteLine(Convert.ToString(c, toBase: 2));
// Output:
// 10110001
İşlenenler için bool
işleç işlenenlerinin |
mantıksal OR değerini hesaplar.
Bileşik atama
İkili işleç op
için formun bileşik atama ifadesi
x op= y
eşdeğerdir
x = x op y
ancak bu x
yalnızca bir kez değerlendirilir.
Aşağıdaki örnekte bit düzeyinde ve vardiya işleçleriyle bileşik atama kullanımı gösterilmektedir:
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}");
Sayısal yükseltmeler nedeniyle, işlemin sonucu op
türüne T
x
örtük olarak dönüştürülebilir olmayabilir. Böyle bir durumda, önceden tanımlanmış bir işleçse ve işlemin sonucu türüne açıkça dönüştürülebilirseop
, formun x op= y
bileşik atama ifadesi ile eşdeğerdirx = (T)(x op y)
, ancak yalnızca x
bir kez değerlendirilir.T
x
Aşağıdaki örnekte bu davranış gösterilmektedir:
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
İşleç önceliği
Aşağıdaki liste, bit düzeyinde sıralar ve en yüksek öncelikten en düşüke kadar değişen işleçleri sıralar:
- Bit düzeyinde tamamlayıcı işleci
~
- Shift işleçleri
<<
,>>
ve>>>
- Mantıksal AND işleci
&
- Mantıksal özel OR işleci
^
- Mantıksal OR işleci
|
İşleç önceliği tarafından uygulanan değerlendirme sırasını değiştirmek için parantezleri ()
kullanın:
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}");
Öncelik düzeyine göre sıralanmış C# işleçlerinin tam listesi için C# işleçleri makalesinin İşleç önceliği bölümüne bakın.
Vardiya işleçlerinin vardiya sayısı
x << count
, x >> count
ve x >>> count
ifadeleri için gerçek vardiya sayısı aşağıdaki türüne x
bağlıdır:
türü
x
veyauint
iseint
, kaydırma sayısı sağ işlenenin düşük sıralı beş biti tarafından tanımlanır. Diğer bir ifadeyle, vardiya sayısı (veyacount & 0b_1_1111
) ilecount & 0x1F
hesaplanır.türü
x
veyaulong
iselong
, kaydırma sayısı sağ işlenenin alt sıralı altı biti tarafından tanımlanır. Diğer bir ifadeyle, vardiya sayısı (veyacount & 0b_11_1111
) ilecount & 0x3F
hesaplanır.
Aşağıdaki örnekte bu davranış gösterilmektedir:
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
Not
Yukarıdaki örnekte gösterildiği gibi, sağ işlenenin değeri sol işlenendeki bit sayısından büyük olsa bile shift işleminin sonucu sıfır dışı olabilir.
Numaralandırma mantıksal işleçleri
~
, &
, |
ve ^
işleçleri de herhangi bir numaralandırma türü tarafından desteklenir. Aynı numaralandırma türündeki işlenenler için, temel alınan tamsayı türünün karşılık gelen değerleri üzerinde mantıksal bir işlem gerçekleştirilir. Örneğin, temel U
x & y
alınan türe sahip bir numaralandırma türünün T
herhangi x
y
biri için ifade, ifadeyle (T)((U)x & (U)y)
aynı sonucu verir.
Genellikle Flags özniteliğiyle tanımlanan bir numaralandırma türüyle bit düzeyinde mantıksal işleçler kullanırsınız. Daha fazla bilgi için Numaralandırma türleri makalesinin Bit bayrakları olarak numaralandırma türleri bölümüne bakın.
İşleç aşırı yüklenebilirliği
Kullanıcı tanımlı bir tür , , <<
, >>
, >>>
, &
, |
ve ^
işleçlerini aşırı yükleyebilir ~
. İkili işleç aşırı yüklendiğinde, buna karşılık gelen bileşik atama işleci de örtük olarak aşırı yüklenir. Kullanıcı tanımlı bir tür, bileşik atama işlecini açıkça aşırı yükleyemez.
Kullanıcı tanımlı bir tür T
, >>
veya >>>
işlecini <<
aşırı yüklerse, sol işlenenin türü olmalıdırT
. C# 10 ve önceki sürümlerde, sağ işlenenin türü olmalıdır int
; C# 11'le başlayarak, aşırı yüklenmiş shift işlecinin sağ işlenen türü herhangi biri olabilir.
C# dili belirtimi
Daha fazla bilgi için C# dil belirtiminin aşağıdaki bölümlerine bakın:
- Bit düzeyinde tamamlayıcı işleci
- Shift işleçleri
- Mantıksal işleçler
- Bileşik atama
- Sayısal yükseltmeler
- C# 11 - Gevşek vardiya gereksinimleri
- C# 11 - Mantıksal sağ kaydırma işleci