1 poin oleh GN⁺ 2024-10-19 | 1 komentar | Bagikan ke WhatsApp
  • P3477R0 adalah usulan perubahan standar agar ukuran byte di C++ tidak lagi bergantung pada nilai CHAR_BIT yang ditentukan implementasi, melainkan ditetapkan tepat 8 bit
  • Platform modern pada dasarnya sudah berkonvergensi dengan asumsi byte 8 bit, dan GCC, LLVM, serta MSVC juga menetapkan nilai bawaan atau makro terkait ke 8
  • POSIX sejak POSIX.1-2001 mewajibkan CHAR_BIT == 8, dan arah adopsi representasi bilangan bulat two’s complement di C++20 dan C23 juga sejalan dengan itu
  • Dukungan untuk byte non-8-bit menyisakan pengecualian kecil di seluruh bahasa, pustaka, dan toolchain, serta menimbulkan beban kasus tepi yang dianggap tidak selaras dengan penggunaan C++ modern di dunia nyata
  • Arsitektur pengecualian seperti PDP-10 atau beberapa DSP memang ada, tetapi pertanyaan utamanya adalah apakah standar C++ baru harus terus mempertahankan kompleksitas demi target tersebut

Tujuan perubahan P3477R0

  • C++ mewarisi makro CHAR_BIT dari C, dan saat ini nilainya merupakan nilai yang ditentukan implementasi untuk menyatakan jumlah bit dalam satu byte
  • P3477R0 mengusulkan agar standar C++ secara resmi mewajibkan byte berukuran 8 bit
  • Pada masa awal komputasi, fleksibilitas untuk mengizinkan berbagai ukuran byte memang bermakna, tetapi penilaiannya adalah bahwa hampir semua perangkat keras modern kini telah berkonvergensi pada asumsi byte 8 bit

Kondisi kompilator dan platform saat ini

  • Kompilator utama pada dasarnya sudah memperlakukan byte 8 bit sebagai kenyataan bawaan
    • GCC menggunakan nilai default 8, dan tidak ada target upstream yang mengubah nilai default ini
    • LLVM menetapkan __CHAR_BIT__ ke 8
    • MSVC mendefinisikan CHAR_BIT sebagai 8
  • Dari contoh dukungan lama di GCC, dsp16xx dihapus pada 2004 dan 1750a dihapus pada 2002
  • Dari penelusuran web memang terlihat beberapa port GCC di luar upstream dengan BITS_PER_UNIT bukan 8, tetapi dinilai tidak tampak relevan dengan C++ modern

Arah POSIX dan representasi bilangan bulat

  • POSIX sejak POSIX.1-2001 mewajibkan syarat berikut
    • byte harus tepat 8 bit
    • CHAR_BIT harus 8
    • SCHAR_MAX harus 127, SCHAR_MIN harus -128, UCHAR_MAX harus 255
  • POSIX menjelaskan bahwa penambahan int8_t mengharuskan char 8 bit dan aritmetika two’s complement
  • C++20 setelah P0907r4 hanya mendukung representasi penyimpanan two’s complement, dan C23 mengikuti arah yang sama
  • Contoh sistem operasi yang saat ini patuh POSIX yang dicantumkan meliputi AIX, HP-UX, INTEGRITY, macOS, OpenServer, UnixWare, VxWorks, dan vz/OS

Biaya yang ditinggalkan byte non-8-bit

  • Perangkat lunak untuk byte 8 bit dan perangkat lunak untuk byte non-8-bit tidak saling kompatibel, dan kode C/C++ untuk target byte non-8-bit pada praktiknya dianggap lebih mirip dialek yang tidak kompatibel dari C dan C++
  • Dukungan untuk arsitektur byte non-8-bit menyisakan kompleksitas kecil namun tidak perlu di berbagai bagian bahasa dan pustaka
  • Kompilator dan toolchain harus terus menanggung kasus tepi yang tidak mencerminkan penggunaan modern
  • Programmer baru mudah bingung karena karakteristik eksotis C++ semacam ini
  • Sebagian programmer berpengalaman juga dianggap menghabiskan waktu pada “portabilitas” untuk platform yang praktis tidak ada

Arsitektur pengecualian dan kompromi

  • Usulan ini juga mengakui bahwa prosesor dengan byte non-8-bit masih ada
  • Pertanyaan intinya adalah apakah prosesor semacam itu masih relevan dengan C++ modern, dan apakah penggunanya benar-benar akan memakai versi C++ baru
  • Sebagai kompromi, diajukan juga opsi untuk mewajibkan CHAR_BIT % 8 == 0, tetapi ini hanya bermakna jika komite memang ingin terus mendukung DSP atau prosesor lain yang CHAR_BIT-nya bukan 8 namun merupakan kelipatan 8
  • PDP-10 termasuk dalam pembahasan, tetapi dibedakan bahwa PDP-11 menggunakan byte 8 bit
  • Sebagian DSP memperlakukan word 24 bit atau 32 bit seperti “byte”, dan arsitektur seperti ini pernah masuk akal pada masa ketika ukuran word beragam dan konsep byte belum distandardisasi

Arah perubahan redaksi standar

  • Definisi byte di intro.memory akan diubah untuk menegaskan bahwa byte, sebagai unit penyimpanan dasar dalam model memori C++, adalah 8 bit
  • Di climits, diusulkan perubahan redaksi agar CHAR_BIT bernilai 8
  • Di cstdint, karena byte adalah 8 bit, tipe bilangan bulat dengan lebar tetap seperti int8_t, uint8_t, dan makro terkait tidak lagi bersifat opsional
  • Untuk tipe yang memakai _N_, jika N bukan 8, 16, 32, atau 64, statusnya tetap opsional
  • Perubahan ini juga mencakup penghapusan 4 klausul mandates terkait CHAR_BIT == 8 di dalam localization

Hubungan dengan standar C

  • Usulan ini meninjau apakah C++ masih perlu terus relevan bagi arsitektur byte non-8-bit
  • Komite C bisa saja mencapai kesimpulan berbeda untuk bahasa C
  • Walaupun idealnya kedua komite selaras, usulan ini menempatkan peran kelompok penghubung WG14 dan SG22 untuk memberikan informasi kepada WG21

1 komentar

 
GN⁺ 2024-10-19
Pendapat di Hacker News
  • Dalam seri JF “Bukankah kita bisa mengakui bahwa komputer nyata memang semuanya bekerja seperti ini?”, sudah ada bagian bilangan bulat bertanda adalah komplemen dua: "Signed Integers are Two’s Complement"

  • Saat magang pada 1986, saya menulis kode C di BBN C/70 yang memakai byte 10-bit; itu pengalaman mengerikan, dan keberadaan mesin seperti itu sejak awal adalah semacam kecelakaan kosmik dalam arti buruk

    • Saya pernah menulis kode di DECSYSTEM-20, tetapi compiler C-nya bukan dukungan resmi
      Mesin itu memakai word 36-bit dan byte 7-bit, dan saat byte diisikan ke word masih ada bit yang tersisa. Lalu saya diberi tugas membaca tape berisi data biner dalam format 8-bit, jadi kacau sekali
    • Saya pernah memprogram CPU Intel Intellivision, mesin aneh yang memakai decl 10-bit, dan tidak cukup kuat untuk menjalankan C
    • Saya pernah bekerja dengan mesin yang memakai byte 9-bit dan instruksi 81-bit, serta mesin yang memakai byte 6-bit, tetapi keduanya tidak punya compiler C
    • Di FPGA masa kini, aritmetika 10-bit sebenarnya tidak jarang dan juga dipakai di produk yang relatif modern
      Namun C 10-bit adalah cerita yang berbeda
  • D membuat kemajuan besar dengan menetapkan hal-hal berikut: byte adalah 8-bit, short 16-bit, int 32-bit, long 64-bit, aritmetika adalah komplemen dua, dan floating point adalah floating point IEEE
    Banyak sekali waktu yang dulu dihabiskan untuk mencoba mengabstraksikan hal-hal seperti ini lalu akhirnya salah pun terselamatkan, dan jutaan orang merasa lega. Set karakternya juga Unicode, bukan EBCDIC atau RADIX-50

    • Zig lebih baik: ukurannya eksplisit seperti u8/i8, u16/i16, u32/i32, u64/i64, dan aritmetikanya juga dipilih secara eksplisit
      Overflow pada + adalah perilaku keliru sehingga dihentikan pada debug dan releasesafe, +% adalah wrapping komplemen dua, dan +| adalah aritmetika saturasi. @addWithOverflow() memberi tuple berisi tipe asli dan u1, sedangkan std.math.add() mengembalikan error saat overflow. f16, f32, f64, f80, f128 juga masing-masing adalah tipe floating point IEEE dengan panjang bit terkait. Berapa panjang byte tidak penting; kalau mesinnya memakai byte 12-bit, tinggal gunakan u12 dan i12
    • Mengatakan D membuat kemajuan besar itu berlebihan. Nama tipe berukuran eksplisit seperti u8, i32 jauh lebih baik dalam segala hal
    • Kalau “byte adalah 8-bit”, seberapa besar bit?
    • Rasanya agak memuji diri sendiri kalau ini dilakukan langsung oleh Bright, penulis bahasa D :)
    • Java juga melakukan bagian ini dengan benar. unsigned ditangani keliru, tetapi standardisasi jumlah bit tipe primitif dilakukan dengan tepat
      byte = 8 bits, short = 16, int = 32, long = 64, float = 32 bit IEEE, double = 64 bit IEEE
  • Masih ada orang yang harus berurusan dengan DSP: https://thephd.dev/conformance-should-mean-something-fputc-and-freestanding#we-cannot-program-on--vibes-
    Secara pribadi, saya sedang mendokumentasikan, sekadar iseng, konsol fantasi 12-bit yang belum diimplementasikan dengan slogan “50% lebih banyak bit per byte dibanding pesaing!”, dan juga memasukkan ciptaan seperti “UTF-12”

    • Saya sedang mencoba memastikan target apa yang masih relevan, dan apakah mereka menargetkan C++ modern atau punya rencana melakukannya
      Sudah bertahun-tahun saya bertanya tetapi belum mendapat jawaban positif; yang disebut hanya TI, jadi saya menambahkan informasinya ke draf pembaruan: https://isocpp.org/files/papers/D3477R1.html
    • Rasanya cukup menargetkan C++23 ke bawah saja. Saya punya beberapa SHARC, tetapi kalau komite menghapus dukungan CHAR_BIT=32 di versi seperti C++30, saya tidak akan menangis sambil protes
    • Bukankah PDP-8 memakai byte 12-bit?
  • Saya penasaran apakah C++ bisa membuang atau menyederhanakan sesuatu
    Ini pertanyaan yang tulus, dan saya tidak mengikutinya secara mendetail. Saya dengar rand() sudah rusak dan tidak bisa diperbaiki, tetapi setahu saya terakhir bahkan belum dijadwalkan untuk deprecated. Proposal ini terlihat seperti ujian: “bisakah kita juga menghapus dukungan untuk solusi atas masalah yang secara harfiah tidak dialami siapa pun?”

    • Integer bertanda tidak harus berupa komplemen dua; tiga representasi, yaitu sign-magnitude, komplemen satu, dan komplemen dua, semuanya valid
      C dan C++ modern membuang itu dan mewajibkan komplemen dua. Di sini pembedaan “as if” juga secara praktis tidak penting, dan karena bisa diterapkan ke CHAR_BIT dengan cara yang sama, jelas ada preseden untuk perubahan semacam ini
    • Trigraph sudah dihapus, dan rand juga sudah dibuat deprecated serta disediakan alternatifnya
      Selain itu ada 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, dan p2186 Removing Garbage Collection Support. Jadi perubahan memang mungkin dilakukan
    • GC API di C++11 dihapus pada C++23, dan itu bisa dimengerti karena tidak dirancang dengan mempertimbangkan kebutuhan varian utama yang mendukung GC, yaitu Unreal C++ dan C++/CLI
      Spesifikasi exception juga dihapus, meski ada orang yang ingin menghidupkannya kembali untuk exception bertipe nilai. auto_ptr juga dihapus karena desainnya rusak. Namun dari sisi penyederhanaan, ini tidak terlalu membaik karena cara lama tetap perlu diketahui
    • Ini tampak seperti sindiran bahwa kita tidak boleh merusak kesempurnaan, melainkan harus menumpuk lebih banyak kesempurnaan
      Seolah-olah C++ membutuhkan simbol baru yang dapat merujuk byte 8-bit secara stabil tanpa merusak kompatibilitas. Misalnya, bisa dibuat unsigned byte8, signed byte8 komplemen dua, dan byte8 dengan perilaku tanda yang tidak didefinisikan. Lalu, sebagai lelucon, untuk akuntan ditambahkan unsigned decimal byte8 dan signed decimal byte8 yang membatasi rentang nilai ke 0~10 dan -10~+10; untuk akuntan yang bahkan memperhitungkan biaya per byte ada centimal byte8 dengan 0~100 dan -100~+100; tipe yang kira-kira cukup untuk field age di database; dan tentu saja float byte8
    • Saya tidak tahu kenapa rand() dianggap rusak. Ia menghasilkan nilai yang tampak acak, dan memang itulah tujuannya
      Tentu saja ia tidak menghasilkan bilangan acak yang aman secara kriptografis, dan fungsi setara di bahasa lain juga begitu. Kalau yang dibutuhkan adalah integer yang cukup acak dan cepat dihitung, rand() bekerja cukup baik
  • Terima kasih atas ketertarikannya pada proposal ini; berdasarkan umpan balik sejauh ini, saya membuat draf pembaruan: https://isocpp.org/files/papers/D3477R1.html

    • Saya suka gaya penulisan proposalnya yang menyindir
      Terutama kalimat ini berkesan: “Masalahnya bukan apakah masih ada arsitektur yang bytenya bukan 8 bit. Ada! Masalahnya adalah apakah mereka peduli pada C++ modern, dan apakah C++ modern peduli pada mereka”
  • Saya punya perasaan campur aduk soal proposal ini. Di satu sisi, ini jelas benar, dan tidak ada penggunaan bermakna untuk CHAR_BIT yang bukan 8
    Di sisi lain, rasanya seperti menyerah pada pandangan dunia yang adil, bahwa dunia harus masuk akal dan bisa ditalar hanya dengan model pribadi yang terlalu disederhanakan tentang isi komputer. Pendekatan seperti ini bisa membawa kita cukup jauh, tetapi pada akhirnya buntu; pada titik terakhir, kita harus mengakui bahwa kita tidak tahu apa-apa dan bahwa argumen formal bahwa program yang kita susun benar hanya berlaku jika dokumentasinya benar. Ini lompatan intelektual yang besar, dan bagi saya pribadi, makin lama saya tidak dipaksa mengakuinya, makin sulit melompatinya nanti. Meski begitu, proyek elektronika fisik tampaknya sedang populer di kalangan pemula sekarang, jadi semoga standar barunya bukan “baca dokumentasinya”, melainkan “baca datasheet sialan itu”

    • Namun setiap kali menjalankan skrip autoconf, saya tetap melihatnya memeriksa jumlah bit dalam satu byte dan menyimpannya di config.h. Seolah-olah ada orang yang benar-benar berencana bertindak berdasarkan nilai itu
    • Kalau sebuah bahasa dipakai luas, pada akhirnya ia akan menabrak masalah COBOL. Dalam kebanyakan kasus tidak apa-apa, tetapi pada sistem tertentu yang dipaksa diperbarui, tiba-tiba sistem kendali lalu lintas bisa berhenti atau pesawat bisa jatuh
      Perlu ada cara untuk memeriksa seluruh kode lama selama proses kompilasi untuk memastikan apakah makro ini sudah digunakan. Perubahan yang memecah kompatibilitas seperti ini juga berisiko membelah bahasa. Tingkat kesulitan untuk menguji apakah codebase lama memakai makro CHAR_BIT dan apakah bisa diperbarui ke compiler baru juga belum jelas. Pertanyaan lain juga muncul, seperti library apa yang akan dianggap rusak, dan apakah masalah juga timbul saat berinteraksi dengan kode lain yang dikompilasi menggunakan CHAR_BIT. Saya setuju ini terasa tidak intuitif, tetapi sebaiknya buat dulu alat konversi dan tunjukkan bahwa peralihan ini aman bahkan pada kasus ekstrem, baru kemudian beralih
  • Saya suka karena ini proposal yang sama sekali sulit dibantah tetapi juga luar biasa pedas

  • Memaksa int8_t == char == 8 bits sepenuhnya oke, tetapi saya tidak yakin soal menyebarkan kesalahpahaman bahwa byte adalah 8 bit
    Byte 8-bit disebut oktet (octet). Pada saat yang sama, sejak C++17 byte juga sudah menjadi semacam “alias” untuk char: https://en.cppreference.com/w/cpp/types/byte

    • Saya pertama kali mengenal komputer 45 tahun lalu, dan saat itu pun “byte” didefinisikan sebagai besaran 8 bit
      Selama 45 tahun berikutnya saya belum pernah melihat “byte” dipakai dengan arti lain, jadi kalau ada definisi “byte” yang bukan 8 bit, saya perlu sumbernya
    • RFC jaringan sejak awal terus memakai istilah octet
    • Tidak, byte itu 8 bit
      Ini bukan pernyataan deskriptif, melainkan pernyataan normatif
    • Secara pribadi saya tidak suka int8 == signed char
      std::cout << (int8_t)32 << std::endl; seharusnya tentu saja mencetak 32
  • Tidak berkaitan dengan C++, tetapi saya cukup menyukai ide mikrokomputer retro dengan byte 6-bit. Jadi 24 bit menjadi satu word
    Mikrokomputer biasanya menangani sedikit objek dan lebih menyukai array daripada pointer, sehingga bisa menghemat memori. VGA memakai 6 bit per warna, alfabet yang masih terbaca bisa dibuat dengan matriks bit 6x4, bahasa dasar seperti LISP atau Forth juga bisa dimasukkan ke alfabet 6-bit, dan System/360 awalnya hanya memakai alamat 24-bit. Memori 12 MiB dengan unit 6-bit yang dapat dialamati secara independen seharusnya cukup untuk siapa pun. Kalau kurang, FAT-12 bisa diperluas secara alami menjadi FAT-24, atau gunakan pointer 48-bit yang sama bergunanya dengan pointer 64-bit

    • Atau cukup gunakan byte 8-bit dan word 3-byte. Tetap saja 24-bit