Merhaba sevgili ziyaretçiler. Bu yazımın konusu C ve C++’ta bit düzeyinde yaptığımız bazı işlemler olacak. C’de veriler üzerinde bit düzeyinde işlemler yapabilmemizi sağlayan ve, veya, değil, özel veya, sola kaydır, sağa kaydır operatörleri vardır. Bu yazıda bitleri sağa ve sola kaydırma işini yapan, iki küçüktür “<<” ve iki büyüktür “>>” işaretleri ile gösterilen bit kaydırma operatörlerinden bahsedeceğiz.
Sola Kaydırma “<<” Operatörü
İki küçüktür ile gösterilen “<<” (Sola Kaydır) operatörü solunda verilen sayının bitlerini sağında verilen sayı kadar bit düzeyinde sola kaydırır. Parametre olarak iki adet sayı alır, birinci parametre ile verilen sayının bitlerini ikinci parametre ile verilen sayı değeri kadar sola kaydırır. Başka bir deyişle, bir “x” tamsayısını “(x<<y)” olarak gösterilen bir “y” tamsayısıyla sola kaydırmak demek, x’i 2^y ile çarpmaya eşdeğerdir.
Aşağıdaki tabloda konunun daha net anlaşılması açısından birkaç örnek yer almakta.
Hex Formatında Bit Kaydırma | İşlemin Sonucu |
0x01 << 1 | 0x02 |
0x02 << 1 | 0x04 |
0x04 << 1 | 0x08 |
0x01 << 2 | 0x04 |
0x01 << 3 | 0x08 |
0x0F << 1 | 0x10 |
İkili Formatta Bit Kaydırma | İşlemin Sonucu |
00000001 << 1 | 00000010 |
00000001 << 2 | 00000100 |
00001111 << 1 | 00011110 |
00001111 << 2 | 00111100 |
Dikkat edeceğiniz üzere sola kaydırma işlemi aslında verilen bir değeri 2’nin üstel katları (2^n) ile çarpmak anlamına geliyor.
Burada vereceğim örnekleri Atmel AVR üzerinden anlatmaya çalışacağım. Örneğin PORTA’nın üzerindeki en düşük değerlikli biti HIGH yapmak istediğinizde bunu en basit haliyle
PORTA = 1;
şekilnde bir atama ile yapabiliyoruz. Biz aslında bu atamayı yapmakla PORTA’ya 00000001 değerini atamış oluyoruz.
Bununla birlikte PORTA üzerindeki en düşük değerli ikinci biti HIGH yapmak istediğimizde ise bunu bit kaydırma operatörü ile kolayca yapabiliriz.
PORTA = (0x01 << 1);
İfadesi ile 0x01 değerini bir kez sola kaydırmış olduk. Böylece PORTA’nın yeni değeri 0x02 olacaktır.
Eğer PORTA’nın en yüksek değerli bitini (yani 7. biti) HIGH yapmak istersek bu sefer de
PORTA = (0x01 << 7);
İfadesini kullanırız. Bu ifade ile 0x01 değerini yedi kez sola kaydırarak 0x80 (Yani 10000000) değerini PORTA’ya atamış oluyoruz.
BİRDEN FAZLA DEĞERİ OR’LAMAK
Bazen birden fazla biti HIGH yapmamız gerekebilir. Böyle durumlarda her bir değeri birbiriyle OR’layarak (VEYA işlemine tabi tutarak) istediğimiz bitleri (diğer bitlerin değerleriyle oynamadan) HIGH yapabiliriz. C ve C++’ta OR (VEYA) işleminin karşılığı “|” (Boru) işaretidir.
PORTA = (1<<0) | (1<<7);
Şunu unutmamak gerekir ki yazdığınız kodlar derleyiciye verilmeden önce bit kaydırma işlemleri ön derleyici tarafından hesaplanır ve böylece yazdığınız kodlar mikrodenetleyici veya işlemci içinde fazladan yer kaplamaz ve işlem gücü tüketmez.
AVR’de Özel Bir Makro: _BV
WinAVR kullananlar _BV makrosunun bit düzeyinde işlemler yaparken ne denli kullanıldığını bilirler. Makronun ne işe yaradığını anlamak için ne yaptığını bilmek gerekir. _BV makrosunun aşağıda verilen tanımı nasıl çalıştığını anlamanızı sağlayacaktır.
#DEFINE _BV(bit) (1 << bit);
Aslında makro oldukça basit değil mi. Kendisine verilen parametreyi alarak “1” değerini bu parametre kadar sola kaydırıyor. Yukarıda yaptığımız işlemleri bir de bu makroyu kullanarak yapalım.
PORTA = _BV(0) | _BV(7);
Bu makro sadece AVR kütüphanesine özel olduğundan diğer C veya C++ implementasyonlarında bulamayabilirsiniz. Eğer illa ki kullanacağım derseniz de makro tanımını kodunuzun tepesinde bir yerlere yazarak makroyu kullanabilirsiniz.
PORT DEĞERİNİN YALNIZCA BİR BİTİNİ HIGH (1) YAPMAK
Eğer port değerinin yalnızca bir bitini güncellemek istersek bunu da tek satırda kolayca halledebiliriz. Mesela portun 3. bitini HIGH yapmak ve diğer bit değerlerini olduğu gibi bırakmak için
PORTA = PORTA | _BV(3);
İfadesini kullanabiliriz. Bu satırda derleyiciye PORTA yazmacının durumunu okumasını ve buradan gelen değerle _BV(3) makrosundan gelen değeri (1 << 3 bit işlemi ile aynı) OR işlemine tabi tutarak sonucu yine PORTA’ya yazmasını söylüyoruz. Sonuç olarak PORTA’nın yalnızca 3. biti HIGH olacak diğer bitleri ise olduğu gibi kalacaktır.
Bu ifadeyi aynı zamanda şöyle de yazabilirdik.
PORTA |= _BV(3);
Bu durumda da yine PORTA’nın içeriği okunarak _BV(3) ile OR’lanacak ve sonuç yine PORTA’ya yüklenecek. |= operatörü ile tek adımda hem OR işlemini hem de atama işlemini yapabiliyoruz.
PORT DEĞERİNİN YALNIZCA BİR BİTİNİ LOW (0) YAPMAK
Bit değerlerini LOW yapmak, HIGH yapmaya benzer. Bir biti LOW yapmak için yeni değerin tersini (tümleyenini) alıp değiştirmek istediğiniz değerle AND’lemeniz (VE) yeterlidir. Cve C++’ta bir değerin tersini (tümleyenini) almak için değerin soluna “~” (tilda) işareti koyarız.
Mesela PORTA’nın birinci bitini LOW (0) yapmak istersek
PORTA &= ~_BV(0);
ifadesini kullanırız. Bu ifadenin ne yaptığına gelecek olursak, diyelim ki PORTA’nın değeri halihazırda 0x55 (yani 01010101) olsun. Eğer bu değerin en düşük değerlikli bitini LOW yapmak istersek PORTA’nın değerini 00000001 değerinin tersi (ya da tümleyeni) olan 11111110 değeri ile AND işlemine tabi tutmamız gerekir.
PORTA | 01010101 |
MASKE | 11111110 |
Mantıksal VE İşlemi | 01010100 |
VE işleminin, LOW yapmak istediğimiz bit hariç diğer bitlerin değerini nasıl koruduğuna dikkat edin. Aşağıdaki satırlarda bu işlemi farklı birkaç yoldan nasıl yapacağımızı görebiliriz.
PORTA &= ~_BV(0x01); PORTA &= ~(1<<0); PORTA = PORTA & ~_BV(0x01); PORTA = PORTA & ~(1<<0);
Sağa Kaydırma “>>” Operatörü
İki büyüktür “>>” işareti ile gösterilen (Sağa Kaydır) operatörü, solunda verilen sayının bitlerini sağında verilen sayı kadar bit düzeyinde sağa kaydırır. Parametre olarak iki sayı alır, birinci parametrede verilen sayının bitlerini ikinci parametre ile verilen değer kadar sağa kaydırır. Başka bir deyişle, bir “x” tamsayısını “(x>>y
)” olarak gösterilen bir “y” tamsayısı kadar sağa kaydırmak, x’i 2^y
ile bölmekle aynı sonucu verir.
Örneğin: N=32
değerini alalım. Bu değerin ikili formdaki karşılığı 0b00100000
bit dizisidir. Şimdi N değerini, 2 ile sağa kaydırırsak yani N=N>>2
yaptığımızda aynı zamanda N=N/(2^2)
olur. Böylece N=32/(2^2)=8
olur. Bunu ikili formda 0b00001000
olarak yazabiliriz.
Sağa kaydırma operatörü ile ilgili bazı örnekler aşağıdaki tabloda verilmiştir.
Hex Formatında Bit Kaydırma | İşlemin Sonucu |
0x01 >> 1 | 0x00 |
0x02 >> 1 | 0x01 |
0x04 >> 1 | 0x02 |
0x08 >> 2 | 0x02 |
0x0A >> 3 | 0x01 |
0x0F >> 1 | 0x07 |
İkili Formatta Bit Kaydırma | İşlemin Sonucu |
00000001 >> 1 | 00000000 |
00001001 >> 2 | 00000010 |
00001111 >> 1 | 00000111 |
00001111 >> 2 | 00000011 |
Bit Kaydırma Operatörleri ile İlgili Bazı Uyarılar
Sola kaydırma ve sağa kaydırma operatörleri negatif sayılarla kullanılmamalıdır. Parametrelerden herhangi biri negatif bir sayıysa, sonucu tanımsız davranış olur. Örneğin, hem 1 >> -1
hem de 1 << -1
‘in sonuçları tanımsızdır.
Bitleri kaydırılacak sayı, bir tamsayı boyutundan daha fazla kaydırılırsa, tanımsız davranış olur. Örneğin, tamsayılar 32 bit kullanılarak depolanıyorsa 1 << 33 tanımsızdır. Daha büyük değerler için bit kaydırma yapılacaksa, büyük değerleri depolayabilen ve 64 bit kullanılarak tanımlanan Unsigned Long Long (ULL) veri tipi kullanılmalıdır. Örneğin: 1ULL << 62ULL
.
Sonraki Yazı: C ve C++’ta Bit Düzeyinde İşlemler – 2: Bit Maskeleme
İlk Yorumu Siz Yapın