Byte düzeyinde değişik
tipteki dizi değişkenler üzerinde işlem yaparken System Namespace’te yer alan
Buffer sınıfı işinizi kolaylaştırabilir. Bu işlemler yapılırken Buffer sınıfının
BlockCopy() metodundan yararlanılmaktadır.
Buffer sınıfının işlevini anlatan veya metotlarının nasıl kullanıldığını
gösteren örnek hazırlamadan önce Array sınıfının Copy() metodundan söz edeceğim.
Bu amaçla int tipinde farklı sayıda elemanlara sahip 2 dizi değişken tanımladım
ve ilk dizinin 3 elemanını Copy() metodu ile ikinciye aktardım.
private void
Form1_Click(object sender, EventArgs e)
{
int[] Dizi_1 = {1,2,3,4};
int[] Dizi_2 = {0,0,0,0,0};
Array.Copy(Dizi_1, 0, Dizi_2, 0, 3);
} |
Hatırlayacağınız gibi Array sınıfının Copy() metodu 1. parametre olarak verilen
dizi değiş¬kenin istenilen elemanından itibaren istenilen sayıda elemanı 3. parametrede
işaret edilen hedef diziye kopyalamaktadır.
Bu kod işletildiğinde Copy() metodu ilk dizinin ilk 3 elemanının
içeriğini ikinci dizinin aynı elemanlarına aktarır ve Dizi_2’nin elemanları
sıra ile “1, 2, 3, 0, 0” değerlerini içerir. Aynı kopyalama işlemini Buffer
sınıfının BlockCopy() metodu ile yapabilirsiniz. Bu metodun nasıl kullanıldığını
aşağıda görebilirsiniz.
private void
Form1_Click(object sender, EventArgs e)
{
int[] Dizi_1 = {1,2,3,4};
int[] Dizi_2 = {0,0,0,0};
System.Buffer.BlockCopy(Dizi_1, 0, Dizi_2,
0, 3);
textBox1.Text = Dizi_2[0].ToString();
textBox2.Text = Dizi_2[1].ToString();
textBox3.Text = Dizi_2[2].ToString();
textBox4.Text = Dizi_2[3].ToString();
} |
Buffer sınıfının
BlockCopy() metodu bu şekilde kullanıldığında beklenenin aksine ilk TextBox’a
1, diğer TextBox’lara ise 0 aktarılır. Aşağıda verilen ekran görüntüsünü bu
kodu işlettikten sonra aldım.
Çünkü BlockCopy() metodunu bu şekilde kullanmakla aslında şöyle bir talepte
bulunmuş oluyoruz: İlk dizinin ilk byte’ından başlamak üzere ikinci diziye 3
byte bilgi kopyala. Belki bu cümle karışık oldu. Şimdi buna açıklık getirmeye
çalışacağım. Madem int değiş¬kenler bellekte 4 byte yer kaplamaktadır int tipindeki
ilk dizi değişkenin bellekteki yerleşimi aşağıdaki gibi resmedilebilir.
int değişkene aktardığım değerler küçük olduğu için en sağdaki byte’lar yeterli
olmaktadır. Bu 4 adet 32 bit bellekte arka arkaya dururlar. BlockCopy() metodunu
aşağıdaki gibi kullanmakla gerçekte ne demiş oluyoruz?
System.Buffer.BlockCopy(Dizi_1, 0, Dizi_2, 0, 3);
Bu 4*4=16 byte’ın
veya 4*4*8= 128 bitin ilk 3 byte’nı veya 8*3=24 bitini kopyala demiş oluyoruz.
Bizim örnekte ilk byte 1, 2. ve 3. byte’larda ise 0 bilgisi olduğu için yukarıda
verilen sonuç alınır. BlockCopy() metodu aşağıdaki gibi kullanılsaydı, başka
bir deyişle kaynak diziden hedef diziye 3 yerine 4 byte kopyalansaydı değişen
bir şey olmazdı.
Çünkü temsili resimden
görebileceğiniz gibi int tipindeki kaynak dizinin ilk elemanın son byte’ının
bütün bitleri 0 ile doludur. Peki BlockCopy() metodu aşağıdaki gibi kullanılmış
olsaydı hedef dizi değişkenin elemanlarının içeriği ne olurdu?
System.Buffer.BlockCopy(Dizi_1,
0, Dizi_2, 0, 5);
4. parametre olarak
5 kullanıldığı için toplam 4 elemanı olan int tipindeki kaynak dizi değiş¬kenin
toplam 16 byte’ın ilk 5 byte veya ilk 40 biti hedef diziye kopyalanır. Kaynak
dizi değiş¬kenin 2. elemanı 2 değerini içeriği için sorunsuz bir şekilde 2.
elemanın içeriği hedef dizideki 2. elemana kopyalanır ve aşağıdaki gibi bir
sonuç alınır.
Şimdi şeytanın avukatlığını yapıp kaynak dizi değişkenin başlangıçta 2 olan
içeriğini 256 yapacağım. Bu şartlarda BlockCopy() metodu ile kaynak dizinin
ilk 5 byte’ı okunup hedef diziye aktarılırsa ne olur?
int[] Dizi_1
= {1,256,3,4};
int[] Dizi_2 = {0,0,0,0};
System.Buffer.BlockCopy(Dizi_1, 0, Dizi_2, 0, 5); |
Bu şartlarda int
tipindeki kaynak dizi değişkenin 2. elamanın veya ikinci 32 bitinin bellek¬teki
temsili yerleşimi aşağıdaki gibi olur. Eleman 256 bilgisini içerdiği için 9.
bit hariç bütün bitler 0 değerini içerir.
Bu durumda int tipindeki kaynak dizi değişkenden 5 byte veya 5*8=40 bit bilgi
okunursa hedef dizinin 2. elemanı 0 olarak kalmaya devam eder. Çünkü 0 olmayan
ilk bit 41. bitte bulunmaktadır. Bu şartlarda yukarıda verilen kod işletilirse
aşağıdaki gibi bir sonuç alınır.
BlockCopy() metodu ile kaynak diziden 5*8=40 byte yerine 6*8=48 byte okunsaydı
hedef dizi değişkenin 2. elemanı 256 olurdu. Kaynak dizinin 2. elemanı 256 yerine
500 sayısını içeriyor olsaydı ve BlockCopy() metodu ile kaynak diziden 5*8=40
byte okunup hedef diziye aktarılmış olsaydı hedef dizinin 2. elamın içeriği
ne olurdu?
Bu sorunun cevabını
yukarıda verdiğim ve BlockCopy() metodunun kullanıldığı kodu işlet¬meden bulmak
istiyorsanız Windows ile birlikte verilen Hesap Makinesi programını çalıştırıp
10 tabanlı 500 sayısının 2 tabanlı karşılığını öğrenerek bulabilirsiniz. 500
sayısını 2 tabanlı olarak ifade etmek için 9 bit yeterli olmaktadır(1 1 1 1
1 0 1 0 0).
Kaynak dizi değişkenin
2. elemanı 500 sayısını içeriyorken BlockCopy() metodu ile 40 byte okursanız
hedef dizi değişkene, kaynak dizi değişkenin aynı sıradaki elemanın ilk 8 byte’ı
kopyalanır ve içeriği 224 olur. Çünkü 2 tabanlı “1 1 1 1 0 1 0 0” sayısının
10 tabanlı karşılığı 224’tür.
int[] Dizi_1
= {1,500,3,4};
int[] Dizi_2 = {0,0,0,0};
System.Buffer.BlockCopy(Dizi_1, 0, Dizi_2, 0, 5); |
Yukarıda belirtildiği
gibi int tipindeki kaynak dizi değişkenimiz 4 elemana sahiptir ve bellekte toplam
4*4=16 byte yer kapmaktadır. Eğer bu örnekte BlockCopy() metoduna 16’dan büyük
bir değeri 5. parametre olarak verirseniz hata meydana gelir.
Yukarıda verdiğim
örnekte kaynak ve hedef dizi değişkenler aynı tipteydi. BlockCopy() metodu farklı
tipteki dizi değişkenleri parametre olarak alıp kopyalama yapabilmektedir. Bu
konuda bilgi vermek için birisi 2 byte’lık Short diğeri 1 Byte’lık byte tipinde
2 dizi değişken tanımladım.
short[] Kaynak_Dizi
= {1000,2000};
byte[] Hedef_Dizi = new byte[10]; |
Bu şekilde tanımlanıp
2 elemanlı olması sağlanan short dizi değişken bellekte 2*2=4 byte veya 2*2*8=32
bit yer kaplar. Bu dizi değişkenin bellekteki yerleşimi aşağıdaki gibi olur.
Şimdi bu kaynak dizinin ilk 3 byte’nı veya 24 bitini BlockCopy()metodu ile okuyup
Byte tipindeki hedef diziye aktaracağım. Başka bir deyişle kaynak dizinin ilk
elamanın bütün bitlerini, 2. elemanın ise ilk 8 bitini okuyacağım.
short[] Kaynak_Dizi
= {1000,2000,3000};
byte[] Hedef_Dizi = new byte[10];
System.Buffer.BlockCopy(Kaynak_Dizi, 0, Hedef_Dizi, 0, 3); |
BlockCopy() metodu bu şekilde kullanıldığında toplam 6 byte bilgi okunduğu için
byte tipindeki hedef dizi değişkenin ilk 6 elemanı doldurulur. Bu elemanların
içeriklerini size göstermek için forma TextBox’lar yerleştirdim ve aşağıda verdiğim
kodu hazırladım.
private void
Form1_Click(object sender, EventArgs e)
{
short[] Kaynak_Dizi = {1000,2000,3000};
byte[] Hedef_Dizi = new byte[10];
System.Buffer.BlockCopy(Kaynak_Dizi, 0, Hedef_Dizi,
0, 3);
textBox1.Text = Hedef_Dizi[0].ToString();
textBox2.Text = Hedef_Dizi[1].ToString();
textBox3.Text = Hedef_Dizi[2].ToString();
textBox4.Text = Hedef_Dizi[3].ToString();
} |
Bu kod işletildiğinde
2 bitlik kaynak dizinin ilk elemanın yarısı byte tipindeki hedef dizinin ilk
elemana, diğer yarısı ise 2. elemana aktarılır. Kaynak dizinin 2. elemanın ilk
byte’ı veya yarısı ise hedef dizideki 3. elemana aktarılır. Bu kod işletildiğinde
aşağıda verilen sonuç alınır.
Yukarıda verilen örneklerde kaynak dizinin eleman sayısını her elemanın bellekte
kapladığı byte miktarını kendim çarpıp hedef dizide gereken eleman sayısını
buldum. Ancak bu hesapların kod yazılarak yapılması gerekir. Buffer sınıfının
ByteLength() metodu parametre olarak aldığı dizi değişkenin bellekte kaç byte
yer kapladığını bulmaktadır. ByteLength() metodu aşağıdaki gibi kullanıldığında
geriye 4*10=40 sayısını gönderir.
private void
Form1_Click(object sender, EventArgs e)
{
int[] Dizi = new int[10];
int sayi = System.Buffer.ByteLength(Dizi);
textBox1.Text = sayi.ToString();
} |
Buffer sınıfının
yukarıda sözü edilen BlockCopy() ve ByteLength() metotlarından başka ayrıca
GetByte() adında bir metodu bulunmaktadır. Bu metot istenen tipteki dizi değişkenin
istenen byte’nın içeriğini okumaya yaramaktadır. GetByte() metodunun nasıl kullanıldığını
aşağıda görebilirsiniz.
private void
Form1_Click(object sender, EventArgs e)
{
short[] Dizi = {100, 1000, 10000};
int ilk_byte = Buffer.GetByte(Dizi, 0);
int ikinci_byte = Buffer.GetByte(Dizi, 1);
int ucuncu_byte = Buffer.GetByte(Dizi, 2);
int dorduncu_byte = Buffer.GetByte(Dizi, 3);
textBox1.Text = ilk_byte.ToString();
textBox2.Text = ikinci_byte.ToString();
textBox3.Text = ucuncu_byte.ToString();
textBox4.Text = dorduncu_byte.ToString();
} |
Bu örnekte GetByte()
metoduna parametre olarak 3 elemanlı short tipindeki dizi değişkeni verdim.
Short tipindeki bu dizi değişkenin her elamanı bellekte 2 byte yer kaplamakta
ve ilk elemana aktarılan sayı ilk byte’a sığdığı için ilk byte’ın içeriği eksiksiz
okunup ilk TextBox’a aktarılır.
Dizi değişkenin
2. elemanın bir kısmı ilk byte’ta, diğer kısmı 2. byte’ta tutulacağı için bu
kod işletildiğinde aşağıdaki gibi bir sonuç alınır. Bit düzeyinde 3. ve 4. byte
birleştirildiğinde 10 tabanlı 1000 sayısı elde edilir.
Herhangi tipteki
dizi değişkenin istediğiniz byte’ına istediğiniz değeri yazmak veya mevcut içeriği
değiştirmek istiyorsanız Buffer sınıfının SetByte() metodunu kullanabilirsiniz.
3 parametreye sahip olan bu metot içeriğinde değişiklik yapılmak istenen dizi
değişkeni ilk parametre olarak almaktadır.
Bu metodun nasıl
kullanıldığını anlatmak için int tipinde ve 3 elemanlı bir dizi değişken tanımladım
ve tanımlama satırında bütün elemanlara 0 aktardım. int tipindeki dizi değişken
3 elaman sahip olduğu için bellekte 3*4=12 byte yer kaplar.
int[] Dizi = {0, 0, 0};
Şimdi SetByte()
metodu ile int tipindeki bu dizi değişkenin 2. elemanın 1. ve 2. byte’larına,
bellekteki sıralamaya göre 5. ve 6. elemanlara 255 sayısını aktaracağım. Sizce
bu kod işletildiğinde int tipindeki dizi değişkenin 2. elemanın içeriği ne olur?
private void
Form1_Click(object sender, EventArgs e)
{
int[] Dizi = {0, 0, 0};
byte Sayi = 255;
System.Buffer.SetByte(Dizi, 4, Sayi);
System.Buffer.SetByte(Dizi, 5, Sayi);
textBox1.Text = Dizi[1].ToString();
} |
Bu kod ile int tipindeki dizi değişkenin 2. elemanın 1. ve 2. byte’larının bütün
bitlerini 1 ile doldurduğum için 2 tabanlı sayı sisteminde 16 adet 1 bir araya
getirildiği zaman 65535 sayısı elde edileceği için TextBox’a 65535 yazılır. Şimdi
bu kodda değişiklik yapıp ayrıca dizi değişkenin 3. byte’ındaki bütün bitlere
1 ile dolduracağım.
private void
Form1_Click(object sender, EventArgs e)
{
int[] Dizi = {0, 0, 0};
byte Sayi = 255;
System.Buffer.SetByte(Dizi, 2, Sayi);
System.Buffer.SetByte(Dizi, 4, Sayi);
System.Buffer.SetByte(Dizi, 5, Sayi);
textBox1.Text = Dizi[0].ToString();
textBox2.Text = Dizi[1].ToString();
} |
Bu kod işletildiğinde int tipindeki dizi değişkenin bellekteki temsili yerleşimi
aşağıdaki gibi olur. 2 tabanlı “111111110000000000000000” sayısının 10 tabanlı
karşılığı 16711680 olduğu için bu kod işletildiğinde ilk TextBox’a 16711680 ve
2. TextBox ise 65535 yazılır.
Makale:
Buffer Sınıfı ile Tamponlama C#, Visual C# ve .NET Memik Yanık
|