Aracılığıyla paylaş


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, int, uint, long, ulong, nint ve nuint türleri için tanı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 , int, uintve long türleri için ulongtanı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 aritmetiklongkaydırma gerçekleştirir: sol işlenenin en önemli bitinin (işaret biti) değeri yüksek sıralı boş bit konumlarına 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ündeyseuint, sağ kaydırma işleci mantıksalulongkaydırma gerçekleştirir: yüksek sıralı boş bit konumları her zaman sıfır olarak 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. Mantıksal kaydırma, soldaki işleneni imzasız bir türe dönüştürmek ve ardından kaydırma işleminin sonucunu imzalı bir türe geri dönüştürmekten daha çok 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

Şu değere eşdeğerdir:

x = x op y

Sadece x 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 Txö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 T bileşik atama ifadesi ile eşdeğerdirx, ancak yalnızca x op= y bir kez değerlendirilir.x = (T)(x op y)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 int ya da uint ise, sağ işlenenin düşük sıralı beş biti vardiya sayısını belirler. Diğer bir ifadeyle, vardiya sayısı (veya count & 0x1F) ile count & 0b_1_1111 hesaplanır.

  • Eğer türü x, long ya da ulong ise, sağ işlenenin düşük-sıralı altı biti kaydırma sayısını tanımlar. Diğer bir ifadeyle, vardiya sayısı (veya count & 0x3F) ile count & 0b_11_1111 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

Her numaralandırma türü ~, &, |, ve ^ işleçlerini destekler. 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 xy alınan türe sahip bir numaralandırma türünün T herhangi Ux & 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. C# 14'den başlayarak, kullanıcı tanımlı bir tür daha verimli bir uygulama sağlamak için bileşik atama işleçlerini açıkça aşırı yükleyebilir. Genellikle, bir tür bu işleçleri aşırı yükler çünkü değer, ikili işlemin sonucunu depolamak için yeni bir örnek ayırma yerine yerinde güncelleştirilebilir. Bir tür açık bir aşırı yükleme sağlamazsa, derleyici örtük aşırı yüklemeyi oluşturur.

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.