Ders 07 / 16
Bayt Sırası
Çok baytlı değerlerin bellekteki yerleşim sırası, küçük ve büyük uçlu gösterim, veri değişiminde doğurduğu sorunlar.
İçindekiler
Buraya kadar bir değerin kaç bitten oluştuğu ve bu bitlerin nasıl yorumlandığı
kuruldu. Bir soru açıkta kaldı: bellek bayt düzeyinde adreslenir, oysa 0x41424344
değeri dört bayttır. Bu dört bayt, ardışık dört adrese hangi sırayla yerleşir?
Sorunun tek bir doğru yanıtı yoktur. Donanım aileleri farklı yanıtlar vermiştir ve bu farklılık, veri iki sistem arasında taşındığında sessiz bozulmalara yol açar. Bu ders, farkı ve ona karşı alınan önlemi tanımlar.
İki Yerleşim
Değerin en anlamlı baytı (most significant byte) 0x41, en az anlamlı baytı
(least significant byte) 0x44’tür. İki yerleşim düzeni vardır:
Büyük uçlu (big-endian) düzende en anlamlı bayt en düşük adrese yazılır:
| Adres | ||||
|---|---|---|---|---|
| Bayt | 41 |
42 |
43 |
44 |
Küçük uçlu (little-endian) düzende en az anlamlı bayt en düşük adrese yazılır:
| Adres | ||||
|---|---|---|---|---|
| Bayt | 44 |
43 |
42 |
41 |
Değer her iki düzende de aynıdır: . Değişen, o değerin bellekteki fiziksel yerleşimidir. Adları, Gulliver’in Gezileri’nde yumurtanın hangi ucundan kırılacağı üzerine çıkan tartışmaya yapılan bir göndermedir; adlandırma, tartışmanın teknik önemi ile pratikte yarattığı yorgunluk arasındaki farkı iyi anlatır.
İki Düzenin Gerekçeleri
Küçük uçlu düzenin savunusu, genişlik dönüşümünün adres değiştirmemesidir. Küçük uçlu bir sistemde 32 bitlik bir değerin bulunduğu adresten tek bayt okunursa, değerin en az anlamlı baytı elde edilir; aynı adresten iki bayt okunursa alt on altı bit elde edilir. Bir değeri daha dar bir tipe daraltmak, adres aritmetiği gerektirmez.
Büyük uçlu düzenin savunusu okunabilirlik ve sıralamadır. Bellek dökümü soldan sağa okunduğunda baytlar, sayının yazıldığı sırayla görünür. Ayrıca çok baytlı değerler bayt bayt karşılaştırıldığında, karşılaştırma sayısal sıralamayla örtüşür; sözlük sıralı anahtar kullanan yapılar için bu bir kolaylıktır.
İki gerekçe de teknik olarak geçerlidir ve seçim büyük ölçüde tarihseldir. Önemli olan, bir sistemin hangi düzeni kullandığının bilinmesi ve veri o sistemin dışına çıkarken düzenin açıkça sabitlenmesidir.
Aynı Baytlar, Farklı Değerler
Sorunun somut hâli şudur: dört bayt 41 42 43 44 bir dosyadan okunduğunda hangi sayı
elde edilir?
- Büyük uçlu okumada:
0x41424344= - Küçük uçlu okumada:
0x44434241=
İki değer arasında elli milyonun üzerinde fark vardır ve hiçbir hata belirtisi oluşmaz; program çalışır, sonucu yanlıştır. Bu, önceki derslerin tekrarladığı ilkenin son hâlidir: baytlar kendi anlamlarını taşımaz, anlam okuma kuralından gelir.
Metin tarafında durum farklıdır. ASCII ve UTF-8, tek baytlık birimlerden oluşan
dizilerdir; bir bayt dizisinin sırası kodlamanın kendisi tarafından belirlenmiştir, bu
yüzden bayt sırası sorunu doğmaz. 41 42 43 44 baytları UTF-8 olarak her sistemde
ABCD okunur.
Buna karşılık UTF-16 ve UTF-32’nin birimleri iki ve dört bayttır; bu kodlamalarda bayt sırası belirtilmek zorundadır. Belirtme yolu, metnin başına bayt sırası imi (byte order mark) olarak U+FEFF kod noktasının yazılmasıdır. UTF-8 metinlerde aynı imin kullanılması gerekmez; bulunması, sırayı değil yalnızca kodlamayı ima eder ve bazı ayrıştırıcılarda beklenmeyen davranışa yol açar.
Ağ Bayt Sırası
Ağ protokolleri, uçlardaki donanımın düzeninden bağımsız olmak zorundadır. Bu nedenle protokol başlıklarındaki çok baytlı alanlar için tek bir düzen sabitlenmiştir: büyük uçlu. Bu sözleşmeye ağ bayt sırası (network byte order) denir.
Program, konak düzeninden ağ düzenine dönüşümü açıkça yapar. Dönüşüm işlevleri, konak düzeni zaten büyük uçluysa hiçbir şey yapmaz; küçük uçluysa baytları ters çevirir. Kodun her iki donanımda da doğru çalışması, bu dönüşümün atlanmamasına bağlıdır.
Aynı disiplin dosya biçimleri için de geçerlidir: ikili bir biçim tanımlanırken alan genişlikleri ve bayt sırası belgede yazılır. Bellek içeriğinin olduğu gibi diske yazılması veya ağa gönderilmesi, biçimi üreten donanıma bağımlı bir dosya üretir.
Uygulamada
Python’da bayt sırası, dönüşüm işlevlerine açıkça bildirilir:
import sys, struct print(sys.byteorder) # çalışılan sistemin düzeni: 'little' veya 'big' deger = 0x41424344 print(deger.to_bytes(4, "big").hex()) # 41424344 print(deger.to_bytes(4, "little").hex()) # 44434241 ham = b"ABCD" # 41 42 43 44 baytları print(hex(int.from_bytes(ham, "big"))) # 0x41424344 print(hex(int.from_bytes(ham, "little"))) # 0x44434241 print(struct.pack(">I", deger)) # b'ABCD' print(struct.pack("<I", deger)) # b'DCBA' print(struct.unpack("!I", b"ABCD")[0]) # 1094861636 — '!' ağ bayt sırası
struct.pack(">I", 0x41424344) çağrısının b'ABCD' üretmesi, bu konunun bütün
derslerini tek satırda birleştirir: aynı otuz iki bit, tam sayı olarak
, kayan noktalı olarak , metin olarak ABCD,
bellekte ise sisteme göre 41 42 43 44 veya 44 43 42 41 dizisidir.
Biçim dizgisindeki ilk karakter düzeni belirtir: < küçük uçlu, > büyük uçlu, !
ağ bayt sırası (büyük uçluya eşdeğer). Bu karakter yazılmazsa çalışılan sistemin düzeni
kullanılır — taşınabilir kodda kaçınılması gereken durum budur.
Bit Sırası ile Karıştırmamak
Uç sırası tartışması baytlar hakkındadır, bitler hakkında değil. Bir baytın içindeki
bitlerin konum değerleri her iki düzende de aynıdır: en anlamlı bit soldadır, en az
anlamlı bit sağdadır. Küçük uçlu bir sistemde 0x41 baytı yine 0100 0001 örüntüsüdür;
ters çevrilmez.
Bit sırası kavramı ayrı bir bağlamda geçerlidir: verinin tel üzerinden seri olarak iletildiği donanım katmanlarında, bitlerin hangi uçtan gönderileceği protokole göre değişir. Bu, yazılımın gördüğü bayt düzeyindeki sıradan bağımsız bir karardır ve ağ müfredatının fiziksel katman konusunda ele alınır.
Üçüncü bir karışıklık kaynağı, bit alanlarının bellek yerleşimidir. Bir yapı içinde bit genişliği belirtilen alanların hangi sırayla paketleneceği, bayt sırasına ek olarak derleyiciye bağlıdır. Bu nedenle bit alanları, taşınabilir olması gereken ikili biçimlerde kullanılmaz; alanlar açık maskeleme ve kaydırma ile üretilir — beşinci dersteki işleçler tam olarak bu iş içindir.
Veri Değişimi Disiplini
Bayt sırası sorunundan kaçınmanın yolu, onu her sınırda açıkça ele almaktır:
- İkili biçimlerde düzen belgelenir. Alan genişlikleri ve bayt sırası, biçim tanımının parçasıdır; okuyucu ve yazıcı aynı belgeye uyar.
- Dönüşüm sınırlarda yapılır. Değer sisteme girerken konak düzenine, çıkarken sabitlenmiş düzene çevrilir; arada kalan kod düzeni hiç düşünmez.
- Bellek içeriği doğrudan taşınmaz. Yapıların ham kopyası; bayt sırasının yanı sıra hizalama ve dolgu (padding) farkları nedeniyle de taşınabilir değildir.
- Metin biçimleri sorunu kendiliğinden çözmez. JSON gibi metin tabanlı biçimlerde bayt sırası sorunu yoktur, ancak bu kez sayısal kesinlik ve kodlama kararları belgelenmelidir.
Bu disiplin, ağ protokolleri ve dosya biçimleriyle çalışan her katmanda tekrar karşınıza çıkacaktır.
Özet
- Çok baytlı bir değerin baytları belleğe iki farklı sırayla yerleşebilir: küçük uçlu düzende en az anlamlı bayt, büyük uçlu düzende en anlamlı bayt en düşük adrestedir.
- Değer aynı kalır, yerleşim değişir; aynı bayt dizisi iki düzende farklı sayı verir.
- Küçük uçlu düzen genişlik daraltmayı adres aritmetiğinden kurtarır; büyük uçlu düzen bellek dökümü okunabilirliği ve sözlük sıralaması sağlar.
- Tek baytlık birimlerden oluşan kodlamalarda (ASCII, UTF-8) bayt sırası sorunu doğmaz; UTF-16 ve UTF-32’de sıra bayt sırası imiyle belirtilir.
- Ağ protokolleri büyük uçlu düzeni sabitler; dönüşüm program tarafından açıkça yapılır.
- İkili veri değişiminde bayt sırası biçim tanımının parçasıdır; ham bellek kopyası taşınabilir değildir.
Sonraki Adım
Bu konu, verinin bellekte nasıl temsil edildiğini kurdu: bitler, tam sayılar, gerçel
sayılar, metin ve bayt yerleşimi. Sırada verinin ne yapıldığı var. Sonraki konu,
belleğin işlemciye nasıl bağlandığını ve bir komutun donanımda hangi adımlarla
yürütüldüğünü ele alacak; orada 0x41424344 örüntüsü bir kez daha, bu kez bir komutun
kendisi olarak karşınıza çıkabilecek bir bit dizisi olarak görünecek.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.