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.

Bu işleçler , uint, longve ulong türleri için inttanımlanır. her iki işlenen de diğer tam sayı türlerinden (sbyte, byte, short, ushortveya 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 intsahip 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, longve ulong türleri için inttanı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, ushortveya 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ündeyseint, 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ına longyayı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ündeyseuint, 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 olarak ulongayarlanı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ç opiç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 >> countve x >>> count ifadeleri için gerçek vardiya sayısı aşağıdaki türüne x bağlıdır:

  • türü x veya uintiseint, 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ı (veya count & 0b_1_1111) ile count & 0x1F hesaplanır.

  • türü x veya ulongiselong, kaydırma sayısı sağ işlenenin alt sıralı altı biti tarafından tanımlanır. Diğer bir ifadeyle, vardiya sayısı (veya count & 0b_11_1111) ile count & 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 Ux & 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:

Ayrıca bkz.