bitsel işlemler – 1

Bitsel işlemleri anlatırken konunun daha iyi anlaşılmasını sağlamak için tamsayıların bitlerini sık sık standart çıkış akımına yazacağız.  Önce bu işi gerçekleştirecek bir işlevi tanımlayalım:

Tanımladığımız bprint işlevi kendisine gönderilen tamsayının bitlerini yazdırmak için Posix işlevi itoa‘yı ve formatlı çıkış işlevi printf‘i kullandı. Şüphesiz bir tamsayının bitlerini yazdırmanın daha iyi yolu doğrudan bitsel işleçleri kullanmak. Bitsel işleçleri ele aldıktan sonra bu işlevin kodunu bu kez doğrudan bitsel işleçleri kullanarak yazacağız.

Önce C’nin tüm bitsel işleçlerini (bitwise operators) tanıyalım:

Bitsel işleçler, bir tamsayının bitleri üzerinde işlemler yaparlar. Daha çok sistem programlarında ya da düşük seviyeli kodlarda kullanılırlar. Bitsel işleçlerin ortak özellikleri, işleme soktukları tamsayıları bir bütün olarak değil, bit bit (bitwise) ele almalarıdır. Bu işleçlerin terimleri (operands) yalnızca tamsayı türlerinden olabilir. Terimlerinin gerçek sayı türlerinden olması geçersizdir.

Aşağıdaki tabloda C dilinde yer alan 11 bitsel işleç daha önce oluşturmuş olduğumuz işleç öncelik tablosundaki öncelik seviyerine göre listeleniyor:

işleç önceliği atom işleç
2 ~ bitsel değil
5 >>
<<
bitsel sağa kaydırma
bitsel sola kaydırma
8 & bitsel ve
9 ^ bitsel özel veya
10 | bitsel veya
14 >>=
<<=
&=
^=
|=
bitsel işlemli atama işleçleri

Yukarıdaki işleçler içinde, yalnızca “bitsel değil” (bitwise not) işleci, tek terimli önek konumunda (unary prefix) bir işleçtir. Diğerleri iki terimli (binary) ara ek konumunda (infix) bulunan işleçlerdir.

bitsel değil işleci
Bitsel değil işleci (bitwise not), diğer tüm tek terimli (unary) işleçler gibi işleç öncelik tablomuzun ikinci seviyesinde yer alıyor. Bu işleç, terimi olan tamsayının bitleri üzerinde 1‘e tümleme (one’s complement) işlemi yaparak bir değer elde eder. Yani terimi olan tamsayının 1 olan bitlerini 0, 0 olan bitlerini 1 yapacak şekilde bir değer üretir. Bu işlecin terimi bir nesne ise bu nesnenin değeri değişmez. Yani işlecin yan etkisi (side effect) yoktur. Aşağıda programı inceleyin:

int türünün 32 bit olduğu benim çalıştığım sistemde örnek bir program çıktısı şu şekildeydi:

Şimdi de şu programı derleyip çalıştıralım:

Bütün bitleri 0 olan 0 tamsayısının bitsel değili bütün bitleri 1 olan sayıdır. Bu sayı işaretli olarak ele alındığında -1 ve işaretsiz olarak ele alındığında işaretsiz int türünün en büyük değeridir,  değil mi?

bitsel kaydırma işleçleri
İki tane bitsel kaydırma işleci (bitwise shift operator) vardır:
Bitsel sağa kaydırma işleci >> (bitwise right shift)
Bitsel sola kaydırma işleci << (bitwise left shift)

Her iki işleç de, (oluşturduğumuz) öncelik tablosunun 5. seviyesindedir. Dolayısıyla bu işleçlerin önceliği tüm aritmetik işleçlerden daha düşük, fakat karşılaştırma işleçlerinden daha yüksektir. Ara ek konumunda bulunan bitsel kaydırma işleçlerinin iki terimleri vardır (binary infix).
Kaydırma işleçlerinin sağ terimi, negatif değerde olmamalı ve sistemin int türünün toplam bit sayısından daha küçük olmalıdır. Bu koşullar sağlanmamış ise oluşan durum tanımsızdır (undefined behaviour). Örneğin Windows sistemlerinde int türden bir değerin 32 ya da daha fazla sola ya da sağa kaydırılması tanımsızdır. Bu durumdan kaçınılmalıdır.

Bitsel sola kaydırma işleci, sol terimi olan tamsayının, sağ terimi olan olan tamsayı kadar pozisyon sola kaydırılmasından elde edilen değeri üretir. Sınır dışına çıkan bitler için, sayının sağından 0 biti ile besleme yapılır. Aşağıdaki kodu inceleyin:

Yukarıdaki kodda yer alan

ifadesi

ifadesi ile aynı anlamdadır.

Bir tamsayıyı, sola bitsel olarak 1 pozisyon kaydırmakla o tamsayının ikiyle çarpılmış değerini elde etmiş oluruz:

Bitsel sağa kaydırma işleci, sol terimi olan tamsayının, sağ terimi olan tamsayı kadar pozisyon sağa kaydırılmış değerini üretir. Sol terim işaretsiz (unsigned) bir tamsayı türünden ise, ya da işaretli (signed) bir tamsayı türünden ancak pozitif değere sahip ise, sınır dışına çıkan bitler yerine, sayının solundan besleme 0 biti ile yapılır. Sağa kaydırılacak ifadenin işaretli bir tamsayı türünden ve negatif değerde olması durumunda sınır dışına çıkan bitler için soldan yapılacak beslemenin 0 ya da 1 bitleriyle yapılması derleyiciye bağlıdır (implementation defined). Yani derleyiciler bu durumda sayının işaretini korumak için soldan yapılacak beslemeyi 1 biti ile yapabilecek bir kod üretebilecekleri gibi, sayının işaretini korumayı düşünmeksizin 0 biti ile besleyecek bir kod da üretebilirler. İşaretli negatif bir tamsayının bitsel sağa kaydırılması taşınabilir bir özellik değildir. Aşağıdaki koda bakalım:

Yukarıdaki kodda

ifadesiyle en yüksek anlamlı biti 1 diğer tüm bitleri 0 olan işaretsiz tamsayı elde ediliyor.

Bir tamsayıyı sağa bitsel olarak 1 kaydırmakla, o sayının ikiye bölünmüş değeri elde edilir:

Bitsel kaydırma işleçlerinin yan etkileri yoktur. Yani sol terimleri bir nesne ise, bu nesnenin bellekteki değeri değişmez. Kaydırma işlemi ile sol terim olan nesnenin değeri değiştirilmek isteniyorsa, bu işleçlerin işlemli atama biçimleri kullanılmalıdır.
Bitsel kaydırma işleçlerinin öncelik yönü soldan sağadır:

x, 16 bitlik işaretsiz bir tamsayı değişken olsun. Yukarıdaki ifade derleyici tarafından

biçiminde ele alınır. Bu ifade ile x değişkeninin ortadaki 8 bitinin tamsayı değeri elde edilir.

bitsel ve işleci 

“Bitsel ve” işleci (bitwise and), işleç öncelik tablomuzun 8. seviyesinde yer alıyor. Bu seviyenin öncelik yönü soldan sağadır (left associative). İşlecin terimleri  nesne gösteren ifadeler ise, bu nesnelerin değerleri değişmez, yani işlecin yan etkisi yoktur. İşlecimiz değer üretmek için terimi olan tamsayıların karşılıklı bitlerini “ve” işlemine sokar. “ve” işlecine ilişkin işlem tablosunu hatırlayalım:

x y x & y
0 0 0
0 1 0
1 0 0
1 1 1

“Bitsel ve” işlecinin ürettiği değer, terimlerinin karşılıklı bitlerinin “ve” işlemine sokulmasıyla elde edilen değerdir:

1 biti “bitsel ve” işleminde etkisiz elemandır.
0 biti “bitsel ve” işleminde yutan elemandır.

“Mantıksal ve” işleci yerine yanlışlıkla “bitsel ve” işlecini kullanmak sık yapılan bir hatadır. Aşağıdaki kodu inceleyin:

Yukarıdaki programda standart giriş akımından alınan x ve y değerlerinin çoğu için hem lojik ve hem bitsel ve işleci için ekrana aynı yazının yazdırıldığını göreceksiniz. Ancak şimdi x 7517 y ise 8866 değerinde olsun:

Bu durumda x && y ifadesinin değeri 1 (lojik doğru) iken x & y ifadesini değeri 0 (lojik yanlış) olacak.

bitsel özel veya İşleci

Bitsel “özel veya” işleci (bitwise exor) işleç öncelik tablomuzun 9. seviyesinde yer alıyor. Bu seviyenin öncelik yönü yine soldan sağadır (left associative). Bu işlecin bir yan etkisi yoktur, yani işlecin terimleri olan nesnelerin değeri değişmez. Bitsel özel veya işlevi terimleri olan tamsayıların karşılıklı bitlerini özel veya (exclusive or) işlemine sokarak bir değer elde eder. Bitsel “özel veya” işlecine ilişkin işlem tablosu aşağıdaki gibidir:

x y x ^ y
0 0 0
0 1 1
1 0 1
1 1 0

Yukarıdaki tablo şöyle özetlenebilir: İşlecin terimlerinden aynı değere sahip ise, üretilen değer 0, terimlerden biri diğerinden farklı ise üretilen değer 1 olur. Aşağıdaki kodu derleyip çalıştırın:

Bir tamsayı, arka arkaya aynı değerle bitsel özel veya işlemine sokulursa, tamsayının kendi değeri elde edilir:

Bazı şifreleme algoritmalarında “özel veya” işleminin bu özelliğinden faydalanılır. 

bitsel veya işleci

“Bitsel veya” (bitwise or) işleci, işleç öncelik tablomuzun 10. seviyesindedir ve bu işlecin öncelik yönü soldan sağadır. Bu işlecin de yan etkisi yoktur, yani terimi olan nesnelerin değeri değişmez.  Bitsel özel veya işlec terimleri olan tamsayıların karşılıklı bitlerini “veya” işlemine sokar. Bitsel veya işlecine ilişkin işlem tablosu şöyledir:

x y x | y
1 1 1
1 0 1
0 1 1
0 0 0

0 biti “bitsel veya” işleminde etkisiz elemandır. 1 biti “bitsel veya” işleminde yutan elemandır.
Aşağıdaki programı derleyerek çalıştırın:

Mantıksal işleçlerden farklı olarak bitsel işleçler kısa devre davranışına sahip değildir. Yani bu işleçlerin her iki terimi de mutlaka işlenir. 

bitsel işlemli atama işleçleri

Bitsel değil işlecinin dışında, tüm bitsel işleçlere ilişkin işlemli atama biçimleri vardır. Daha önce de belirtildiği gibi bitsel işleçlerin yan etkileri (side effect) yoktur. Bitsel işleçler terimleri olan nesnelerin bellekteki değerlerini değiştirmez. Bir bitsel işleç ile bir nesnenin değerinin değiştirilmesi isteniyorsa yazma ve okuma kolaylığı için için işlemli atma işleçleri tercih edilmelidir:

ifadeleri kullanılabilir.

Bitsel özel veya işlemli atama işleçleriyle, tamsayı türlerinden iki değişkenin değerlerinin, üçüncü bir değişken kullanılmadan takas (swap) edilmesi sık kullanılan bir C idiyomudur:

Yukarıdaki programda, x ve y değişkenlerinin değerleri takas ediliyor.

Necati Ergin

C ve Sistem Programcıları Derneğinde eğitmen olarak çalışıyor.

Bunlar da ilginizi çekebilir

bitsel işlemler – 1” için bir yorum

  1. Bu makale ve ayrıca bitsel işlemler – 2’yi okuyunca, süpersiniz hocam demekten kendimi alamadım, sanki gömülü sistem programlama (Embedded system programming ) üzerine anlatıyormuş gibi derine inmişsiniz TEŞEKKÜRLER…

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Kod Eklemek İçin Okuyun