C++ önerisi: Bayt tam olarak 8 bit olsun
(open-std.org)- P3477R0, C++’ta bayt boyutunu
CHAR_BITadlı uygulama tanımlı bir değere bırakmak yerine tam olarak 8 bit olarak sabitlemeyi öneren bir standart değişikliği teklifidir - Modern platformlar zaten 8 bit bayt varsayımında birleşmiş durumda; GCC, LLVM ve MSVC de ilgili varsayılan değerleri veya makroları 8 olarak belirliyor
- POSIX, POSIX.1-2001’den beri
CHAR_BIT == 8şartını arıyor; C++20 ve C23’teki iki’nin tümleyeni tamsayı gösterimi benimseme eğilimi de aynı yönde - 8 bit olmayan bayt desteğinin dil, kütüphane ve toolchain genelinde küçük istisnalar bıraktığı; modern C++ kullanımıyla örtüşmeyen uç durum yükü oluşturduğu düşünülüyor
- PDP-10 veya bazı DSP’ler gibi istisnai mimariler mevcut olsa da, yeni C++ standardının bu hedefler için karmaşıklığı sürdürmeye devam edip etmemesi temel tartışma noktası
P3477R0’ın değişiklik hedefi
- C++, C’deki
CHAR_BITmakrosunu devralır; mevcut durumda bu değer, bir bayttaki bit sayısını ifade eden uygulama tanımlı bir değerdir - P3477R0, C++ standardının baytı resmen 8 bit olarak şart koşacak şekilde değiştirilmesini öneriyor
- Bilgisayarların ilk dönemlerinde farklı bayt boyutlarına izin veren esnekliğin anlamlı olduğu, ancak modern donanımın neredeyse tamamen 8 bit bayt varsayımında birleştiği değerlendirmesi temel alınıyor
Derleyicilerin ve platformların mevcut durumu
- Başlıca derleyiciler 8 bit baytı zaten varsayılan gerçeklik olarak ele alıyor
- GCC’nin geçmiş destek örneklerinden
dsp16xx2004’te,1750aise 2002’de kaldırıldı - Web aramalarında
BITS_PER_UNITdeğeri 8 olmayan bazı GCC dışı portlar görülse de bunların modern C++ ile ilgili görünmediği değerlendiriliyor
POSIX ve tamsayı gösterimindeki yönelim
- POSIX, POSIX.1-2001’den beri şu koşulları şart koşuyor
- Bayt tam olarak 8 bittir
CHAR_BIT,8dirSCHAR_MAX127,SCHAR_MIN-128,UCHAR_MAXise255tir
- POSIX,
int8_teklenmesinin sonucu olarak 8 bitcharve iki’nin tümleyeni aritmetiğini gerektirdiğini açıklıyor - C++20, P0907r4 sonrasında yalnızca iki’nin tümleyeni depolama biçimini destekliyor; C23 de aynı yönü izliyor
- POSIX uyumlu güncel işletim sistemi örnekleri olarak AIX, HP-UX, INTEGRITY, macOS, OpenServer, UnixWare, VxWorks ve vz/OS listeleniyor
8 bit olmayan baytların bıraktığı maliyet
- 8 bit bayt için yazılmış yazılım ile 8 bit olmayan bayt için yazılmış yazılım birbiriyle uyumlu değildir; 8 bit olmayan bayt hedefli C/C++ kodunun fiilen C ve C++’ın uyumsuz lehçelerine yakın olduğu düşünülüyor
- 8 bit olmayan bayt mimarilerini desteklemek, dilin ve kütüphanenin birçok bölümünde küçük ama gereksiz bir karmaşıklık bırakıyor
- Derleyiciler ve toolchain’ler, modern kullanımı yansıtmayan uç durumları taşımaya devam etmek zorunda kalıyor
- Yeni programcıların C++’ın bu egzotik özellikleri nedeniyle kolayca kafa karışıklığı yaşaması olası
- Bazı deneyimli programcıların da var olmayan platformlar için “taşınabilirlik” üzerine zaman harcadığı değerlendiriliyor
İstisnai mimariler ve uzlaşma seçenekleri
- Öneri, 8 bit olmayan bayt işlemcilerinin hâlâ var olduğunu kabul ediyor
- Temel soru, bu işlemcilerin modern C++ ile ilgili olup olmadığı ve bu işlemcilerin kullanıcılarının yeni C++ sürümlerini kullanıp kullanmayacağı
- Uzlaşma olarak
CHAR_BIT % 8 == 0şartının aranması da öneriliyor; ancak bu yalnızca komiteninCHAR_BITdeğeri 8 olmayan ama 8’in katı olan DSP’leri veya diğer işlemcileri desteklemeye devam etme kararı alması durumunda anlamlı - PDP-10 tartışma konusu olsa da PDP-11’in 8 bit bayt kullandığı ayrıca belirtiliyor
- Bazı DSP’ler 24 bit veya 32 bit word’leri “bayt” gibi ele alıyor; bu tür mimariler, word boyutlarının çeşitli olduğu ve bayt kavramının standartlaşmadığı dönemlerde makuldü
Standart metnindeki değişiklik yönü
intro.memoryiçindeki bayt tanımını değiştirerek C++ bellek modelinin temel depolama birimi olan baytın 8 bit olduğunu açıkça belirtmek amaçlanıyorclimitsiçindeCHAR_BITdeğerini8olarak belirleyen yönde metin değişikliği öneriliyorcstdintiçinde, bayt 8 bit olacağı içinint8_t,uint8_tgibi genişliği belirtilmiş tamsayı tipleri ve ilgili makrolar artık isteğe bağlı olmayacak_N_kullanan tiplerdeNdeğerinin8,16,32,64olmadığı durumlar ise isteğe bağlı kalmaya devam edeceklocalizationiçindekiCHAR_BIT == 8ile ilgili 4 mandate hükmünün kaldırılmasını içeren bir değişiklik de yer alıyor
C standardıyla ilişkisi
- Öneri, C++’ın 8 bit olmayan bayt mimarileriyle ilgili kalmaya devam edip etmemesi gerektiğini değerlendiriyor
- C komitesi, C dili için farklı bir sonuca varabilir
- İki komitenin hizalanması ideal olsa da bu öneri, WG14 ve SG22 irtibat grubunun WG21’e bilgi sağlaması yönünde konumlanıyor
1 yorum
Hacker News görüşleri
JF’nin “gerçek bilgisayarların zaten böyle çalıştığını kabul edemez miyiz?” serisinde daha önce işaretli tamsayılar 2’nin tümleyeni kullanır başlıklı bir bölüm vardı: "Signed Integers are Two’s Complement"
Ama o zaman Linux çekirdeğindeki şu klasik kod eskimiş hale gelebilir: https://github.com/torvalds/linux/blob/master/include/math-emu/double.h#L29
1986’da stajyerken 10 bit bayt kullanan BBN C/70 üzerinde C kodu yazmıştım; korkunç bir deneyimdi ve böyle bir makinenin en başta var olmuş olması bile olumsuz anlamda kozmik bir kazaydı
36 bit word ve 7 bit bayt kullanıyordu; baytları bir word’e doldurunca artan bitler kalıyordu. Üstüne bir de 8 bit formatında ikili veri içeren bantları okuma görevi verilince tam bir felaket olmuştu
Ama konu 10 bit C olunca durum değişiyor
D, şu kararları vererek büyük bir ilerleme sağladı: bayt 8 bit, short 16 bit, int 32 bit, long 64 bit, aritmetik 2’nin tümleyeni, kayan nokta ise IEEE floating point
Bunları soyutlamaya çalışıp sonunda yine hata yapmaya harcanan muazzam zaman tasarruf edildi ve milyonlarca insan rahat bir nefes aldı. Karakter kümesi de EBCDIC ya da RADIX-50 değil, Unicode oldu
u8/i8,u16/i16,u32/i32,u64/i64gibi boyutlar açıkça belirtiliyor ve aritmetik de açık seçik seçiliyor+taşması hatalı davranış sayılır; debug ve releasesafe modlarında durur,+%2’nin tümleyenine göre wrapping,+|ise doygun aritmetiktir.@addWithOverflow()özgün tür ileu1içeren bir tuple verir,std.math.add()ise taşma durumunda hata döndürür.f16,f32,f64,f80,f128de sırasıyla o bit uzunluklarındaki IEEE floating point türleridir. Baytın kaç bit olduğu önemli değildir; 12 bit bayt kullanan bir makinedeu12vei12kullanırsınızu8,i32gibi tür adları her bakımdan çok daha iyiunsignedtarafını kötü ele aldı ama temel türlerin bit sayısını standartlaştırma işini doğru yaptıbyte = 8 bits,short = 16,int = 32,long = 64,float = 32 bit IEEE,double = 64 bit IEEEHâlâ DSP ile uğraşmak zorunda olan insanlar var: https://thephd.dev/conformance-should-mean-something-fputc-and-freestanding#we-cannot-program-on--vibes-
Ben ise kişisel olarak, “rakibe göre bayt başına %50 daha fazla bit!” diye pazarlanan, hiç uygulanmamış bir 12 bit fantezi konsolu eğlencesine dokümantasyon yazıyorum; içine “UTF-12” gibi icatlar da koydum
Bunu yıllardır soruyorum ama olumlu bir yanıt alamadım; adı geçen tek örnek TI olduğu için güncel taslağa bilgi ekledim: https://isocpp.org/files/papers/D3477R1.html
CHAR_BIT=32desteğini kaldırsa buna ağlayarak itiraz edecek değilimC++'ın bir şeyi kullanımdan kaldırıp veya basitleştirip basitleştiremeyeceği merak ediliyor
Dürüst bir soru; ayrıntıları yakından takip etmedim.
rand()'ın bozuk olduğu ve düzeltilemeyeceği söyleniyordu; en son bildiğim kadarıyla hâlâ kullanımdan kaldırılma yolunda bile değildi. Bu öneri, “kelimenin tam anlamıyla kimsenin karşılaşmadığı bir soruna çözüm desteğini de kaldırabilir miyiz?” testi gibi görünüyorModern C ve C++ bunu bırakıp 2'nin tümleyenini zorunlu kıldı. Burada “as if” ayrımı da pratikte pek önemli değil ve aynı yaklaşım
CHAR_BITiçin de uygulanabilir; yani böyle bir değişimin emsali açıkça varrandde kullanımdan kaldırılacak olarak işaretlendi ve alternatifleri de sunulduBunun dışında
p2809 Trivial infinite loops are not Undefined Behavior,p1152 Deprecating volatile,p0907 Signed Integers are Two's Complement,p2723 Zero-initialize objects of automatic storage duration,p2186 Removing Garbage Collection Supportda var. Yani bir şeyleri değiştirmek mümkünİstisna belirtimleri de kaldırıldı, ama değer tipi istisnalar için bunları geri getirmek isteyenler de var.
auto_ptrda bozuk tasarımı yüzünden kaldırıldı. Yine de basitleştirme açısından çok bir iyileşme yok; çünkü eski yöntemi hâlâ bilmek gerekiyorYani uyumluluğu bozmadan 8 bit baytı güvenilir biçimde ifade eden yeni bir C++ simgesi gerekirmiş gibi. Mesela
unsigned byte8, 2'nin tümleyenisigned byte8, işaret davranışı tanımlanmamışbyte8yapılabilir. Muhasebeciler için değer aralığı 0~10, -10~+10 ile sınırlıunsigned decimal byte8vesigned decimal byte8, bayt maliyetini bile hesaplayan muhasebeciler için 0~100, -100~+100 aralıklıcentimal byte8, veritabanındakiagealanı için aşağı yukarı yeterli bir tür ve tabii kifloat byte8da ekleyelim diye dalga geçiliyorrand()'ın neden bozuk olduğunu bilmiyorumRastgele görünen değerler üretiyor ve amaç da bu. Kriptografik olarak güvenli rastgele sayılar üretmemesi doğal; başka dillerdeki eşdeğer işlevler de aynı. Hızlı hesaplanan, yeterince rastgele tamsayılar gerekiyorsa
rand()gayet yeterli çalışıyorÖneriye ilgi gösterdiğiniz için teşekkürler; şimdiye kadar gelen geri bildirimlere dayanarak güncellenmiş bir taslak hazırladım: https://isocpp.org/files/papers/D3477R1.html
Özellikle “Sorun, baytın 8 bit olmadığı mimarilerin hâlâ var olup olmaması değil. Varlar! Sorun, onların modern C++'ı önemseyip önemsemediği ve modern C++'ın onları önemseyip önemsemediğidir” cümlesi etkileyici
Bu öneriye karşı karışık duygularım var. Bir yandan açıkça doğru ve
CHAR_BIT'in 8 olmamasının anlamlı bir kullanım alanı yokÖte yandan, dünyayı yalnızca bilgisayarların iç işleyişine dair kişisel ve aşırı basitleştirilmiş bir modelle mantıklı ve akıl yürütülebilir kılmak isteyen adil dünya yanılgısına teslim olmak gibi de hissettiriyor. Bu yaklaşım bir yere kadar çok işe yarıyor ama sonunda çıkmaz sokağa giriyor; en nihayetinde hiçbir şey bilmediğinizi ve doğru programı ancak belgeler doğruysa kurduğunuza dair biçimsel bir argümanın elinizdeki en iyi şey olduğunu kabul etmek gerekiyor. Bu büyük bir zihinsel sıçrama ve kişisel olarak buna ne kadar geç zorlandıysam sonradan aşması o kadar zor oldu. Yine de bugünlerde yeni başlayanlar arasında fiziksel elektronik projeleri popülerleşiyor gibi; bu yüzden umarım “belgeleri oku” yerine “lanet olası datasheet'i oku” yeni standart olur
autoconfbetiği çalıştırdığımda bir bayttaki bit sayısını kontrol edip bunuconfig.hiçine yazdığını görüyorum. Sanki biri gerçekten o değere göre davranmayı planlıyormuş gibi görünüyorÖnceki kodun tamamını derleme sırasında tarayıp bu makronun zaten kullanılıp kullanılmadığını kontrol edecek bir yol gerekli. Böyle kırıcı değişiklikler dili parçalama riski de taşır. Mevcut kod tabanlarının
CHAR_BITmakrosunu kullanıp kullanmadığını ve yeni bir derleyiciye güncellenip güncellenemeyeceğini test etmenin zorluğu da net değil. Hangi kütüphanelerin kırılmış sayılacağı veyaCHAR_BITkullanılarak derlenmiş başka kodlarla etkileşimde de sorun çıkıp çıkmayacağı gibi sorular da var. Sezgilere aykırı olduğuna katılıyorum, ama önce dönüştürme araçları üretip en uç durumlarda bile güvenli olduğunu gösterdikten sonra geçmek daha iyi olurTartışmaya kapalı olduğu hâlde inanılmaz derecede acı bir öneri; bu yüzden hoşuma gidiyor
int8_t == char == 8 bitszorunluluğu tamamen kabul edilebilir, ama baytın 8 bit olduğu yanılgısını yayma konusunda emin değilim8 bitlik bayta octet denir. Ayrıca C++17'den beri
byte, zatenchariçin bir tür “takma ad” gibi: https://en.cppreference.com/w/cpp/types/byteSonraki 45 yıl boyunca “byte”ın başka bir anlamda kullanıldığını hiç görmedim; dolayısıyla 8 bit olmayan bir “byte” tanımı varsa bunun için kaynak görmek isterim
Bu betimleyici bir ifade değil, kural koyucu bir ifade
int8 == signed charolmasından hoşlanmıyorumstd::cout << (int8_t)32 << std::endl;doğal olarak 32 yazdırmalıdırC++ ile ilgili değil ama, 6 bitlik bayt retro mikrobilgisayar fikri kulağıma oldukça hoş geliyor. Böylece 24 bit bir sözcük oluyor
Mikrobilgisayarlar genelde az sayıda nesneyle çalışır ve pointer'lardan çok dizileri tercih eder, bu yüzden bellekten tasarruf edilebilir. VGA'de renk başına 6 bit vardı, 6x4 bitlik bir matrisle okunabilir alfabeler oluşturulabilir, temel LISP ya da Forth dilleri de 6 bitlik bir alfabeye sığdırılabilir ve orijinal System/360 da yalnızca 24 bit adres kullanıyordu. Bağımsız olarak adreslenebilen 6 bitlik birimlerden oluşan 12MiB bellek herkes için yeterli olmalı. Yetmezse FAT-12 doğal biçimde FAT-24'e genişletilebilir ya da 64 bit pointer'lar kadar kullanışlı 48 bit pointer'lar kullanılabilir