Haftalık C++ 41 – “Endiannes”

Tekrar merhaba sevgili yazılımperver dostlarım. Bugün sizlerle birlikte, belki de birçoğunuzun hiç farkında olmadığı ya da kullanırken pek farketmediği bir konuya değineceğim, “Endianness”.

Eğer masaüstü ya da web ya da mobil bir yazılım geliştiricisiyseniz, bu kavramla hiç tanışmamış olabilirsiniz. Hatta, gömülü yazılım geliştiricisi iseniz ve eğer tek bir işlemci ailesi ile çalışma fırstı yakalamış çok şanslı bir azınlık içerisindeyseniz, bu kavramı yine duymamış olabilirsiniz. Fakat, farklı işlemci mimarileri ve haberleşme protokolleri ile çalışmışsanız, bu yazım ilginizi çekebilir.

Bu yazımda, bu kavramı masaya yatırıp, ne anlama geldiğine, bize yansımalarının ne olduğuna ve bunu nasıl kotaracağımıza bakıyor olacağız.

Öncelikle bunun ne olduğuna bir bakalım. Bunun için de birinci kaynağımız elbette wikipedia. Türkçe kısmı çok detaylı değil ve yanlış yönlendirebilir ama ingilizce kısmı oldukça detaylı, okumanız iyi olur, elbette ben burada önemli noktaları sizler ile paylaşacağım. Öncelikle tanımına bir bakalım. Elbette, hepsinin üzerine C++ da serpiştireceğiz 😉

“Endianness” aslında değerlerin/sayısal verilerin, byte olarak bellekte tutulma sırasına verilen isim (benzer şekilde haberleşme kanalları üzerinden gönderilme sırası). Günümüz dünyasında kullandığımız bilgisayar mimarileri, yazma ve okuma işlemleri için kullandıkları en küçük birim byte’dır. Bir çok işlemci, bellekteki sayısal verilere byte olarak erişmeye imkan verirler, fakat birden fazla byte söz konusu olduğunda, ilgili yaklaşım önem arz eder. İki dominant “endianness” yaklaşımı bulunmaktadır. Bunlar “big-endian (BE)” ya da “little-endian (LE)” ‘dır.

“Big endian” sistemlerde, ilgili dijital verinin en yüksek byte’ı en küçük adreste, en düşük byte’ı ise en büyük adreste tutulur. “Little endian” sistemlerde ise bunun tam tersi geçerlidir. Örneğin, elimizde 16 bit’lik bir short değişkeni olduğunu düşünelim. Bu değişken temelde iki byte’dan oluşmakta. 0-7 bitleri düşük byte’ı, 8-15 bitleri ise büyük byte değerini tutar. Buraya kadar aslında “endianness” ın bir etkisi yok. Ne zaman ki, bu byte’lar bellekte nasıl tutulur diye sorduğumuzda ya da örneğin seri kanal üzerinde ilk hangi byte gönderilir dediğimizde, “endianness” önem kazanır.

Kullanıdığımız İntel ve AMD işlemciler, “little-endian” yaklaşımını kullanmaktadır. Bazı Power PC, IBM z mimarileri ise “big-endian” yaklaşımını kullanmaktadır. Ayrıca, ağ protokollerinde de “big-endian” yaklaşımı dominanttır.

Şimdi elimizde 43981 sayısı olduğunu düşünelim. Bu sayının byte dizilimi 16’lık düzende şu şekildedir : 0xABCD. Bu sayının, MSB’si (“most significant byte”) AB ve rakamı da (16 lık düzende), A’dır. Bu sayının, iki yaklaşıma göre nasıl ifade edildiğine hemen bir figür ile bakalım:

Sanırım, bu figür, sizler için bu iki yaklaşımı özetlemek adına faydalı olmuştur.

Şimdi, azıcık kodlama yapalım. Örneğin, elimizdeki bir sayının bellekteki byte dizilimini görebilir miyiz? Elbette, hemen bakalım:

Bu kodu, “little endian” bir makinede çalıştırırsanız ” CD AB” görürsünüz. Tam tersi, “big endian” bir makinede çalıştırırsanız ” AB CD” görürsünüz.

Peki yazılımsal olarak, şu an kodumuzun çalıştığı makinenin “endianness” yaklaşımını öğrenebilir miyiz? Evet, onu da öğrenebiliriz. Nasıl mı, hemen bakalım.

Evet,  gelelim yazımızın 10 puanlık sorusuna. “Endiannes” olayı benim yoluma ne zaman çıkar?

  • Farklı işlemci mimarileri ile haberleşen bir yazılımınız var ise,
  • Ya da farklı işlemci mimarileri tarafından, bellek verilerinin üretildiği dosyalar ile uğraşıyorsanız.

Elbette, bu tarz haberleşen sistemlere ilişkin bir protokol tasarlıyorsanız, kaynak sistemin “endianness”‘ına ilişkin bir bitlik bilgiyi mesajlarınız içine gömebilirsiniz ve kim neye sahip duyurabilirsiniz 😉

Velev ki, baktınız elinizdeki veri, sizin makinenizin “endiannes” ı ile uyumlu değil ne yapacaksınız. Eğer QT kullanıyorsanız, işiniz kolay. Verileri dönüştürmek için QDataStream tek kaynak olarak kullanabileceğiniz, donanımlı ve oldukça yakışıklı bir sınıf. Bu sınıf saysesinde, farklı boyutlarda verileri belirleyeceğiniz “endianness” yaklaşımına göre, byte dizisine çevirebilir ya da byte dizisi olarak aldığınız verilerden ilgili sayıları üretebilirsiniz. Ayrıca sayıları dönüştürmek için <QtEndian> başlık dosyası içerisinde de bir takım yardımcı fonksiyonlar mevcut. Bu sınıflardan esinlenerek kendi sınıflarınızı da yazabilirsiniz, misal ben zamanında bir aviyonik projesi için DataStream sınıfı yazdıydım.

Yazımı bitirmeden, kod bohçamın içerisinde, teee 2017’de, yazdığım bir sınıfı da sizler ile paylaşıyorum, tepe tepe kullanabilirsiniz. O zamanlar yazılan bu sınıf, bu satıra kadar yazdığım bir çok noktayı içerisinde barındırıyor. Özellikle GetSystemByteOrder() tek başına kullanılabilir, ayrıca “variadic template” ‘ların kullanımına da güzel bir örnek oldu ne dersiniz 😉

UENGINE kullanımı dikkatinizi çekmiştir, nereden geliyor diye merak ediyorsanız, zamanıdna giriştiğim, üç dört iterasyon oyun motoru çalışmalarından geliyor. U’nun nereden geldiği ise şimdilik ben de kalsın 😛

Bu arada, bu ve benzeri kod parçalarını da https://github.com/yazilimperver altına bir proje açıp toplamayı planlıyorum, ne dersiniz? Görüşlerinizi bekliyorum.

Bir sonraki yazıma kadar kendinize çok iyi bakın sevgili yazılımperver dostlarım.

Kaynaklar:

Bir cevap yazın

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

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.