"Enter"a basıp içeriğe geçin

C ve C++’ta Bit Düzeyinde İşlemler – 1: Bit Kaydırma Operatörleri

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 << 10x02
0x02 << 10x04
0x04 << 10x08
0x01 << 20x04
0x01 << 30x08
0x0F << 10x10
İkili Formatta Bit Kaydırmaİşlemin Sonucu
00000001 << 100000010
00000001 << 200000100
00001111 << 100011110
00001111 << 200111100

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.

PORTA01010101
MASKE11111110
Mantıksal VE İşlemi01010100

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 >> 10x00
0x02 >> 10x01
0x04 >> 10x02
0x08 >> 20x02
0x0A >> 30x01
0x0F >> 10x07
İkili Formatta Bit Kaydırmaİşlemin Sonucu
00000001 >> 100000000
00001001 >> 200000010
00001111 >> 100000111
00001111 >> 200000011

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

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir