- Memasuki 2023, cara menulis kode C berubah cukup besar, dan gayanya ditata ulang dengan berfokus pada nama tipe pendek, menyingkirkan string null-terminated, pengembalian struct, dan kompilasi unit translasi tunggal
- Alias pendek seperti
u8,i32,size,s8serta penghapusanconstdanstructdipilih untuk mengurangi noise visual dan beban kognitif dari deklarasi yang berulang - String ditangani bukan dengan cara null-terminated, melainkan sebagai fat pointer
s8yang memilikidatadanlen, dan pada lingkungan Win32·UTF-16,c16dans16juga digunakan bersama - Dalam desain fungsi, pengembalian struct lebih disukai daripada parameter out, dan digunakan pola nilai kembalian yang diinisialisasi nol lalu
okhanya diset saat berhasil - Hingga makro, assert, deklarasi Win32, dan inline assembly, aturan lokal yang mudah dibaca diprioritaskan, tetapi saat berkontribusi ke proyek lain, gaya proyek tersebut tetap diikuti
Menunjukkan niat dengan nama tipe pendek
- Untuk tipe integer·karakter·ukuran pointer dasar, digunakan alias pendek
- Contoh:
u8,c16,b32,i32,u32,u64,f32,f64,uptr,byte,size,usize
- Contoh:
- Nama-nama ini sering muncul di seluruh program, sehingga keringkasan memberi keuntungan langsung saat membaca dan meninjau kode
- Sufiks
_ttidak lagi digunakan, dan kini terasa sebagai elemen yang mengganggu secara visual - Untuk prefiks tipe signed,
ilebih disukai daripadassdibiarkan tersedia untuk nama tipe string
- Untuk tipe ukuran, digunakan
sizealih-alihisize- Karena signed size dianggap sebagai nilai default dasar yang lebih penting
usizeterutama dipakai dalam kasus sempit saat berinteraksi dengan antarmuka eksternal
b32menunjukkan niat sebagai “boolean 32-bit”- Menggunakan ukuran word yang terasa alami alih-alih
_Bool - Dalam praktiknya, nilainya sering dianggap berada di register atau masuk ke padding struct
- Saat memori benar-benar penting, boolean dipadatkan ke dalam variabel
flags
- Menggunakan ukuran word yang terasa alami alih-alih
c16adalah tipe karakter untuk UTF-16 yang diperlukan di Win32- Bila berbasis
char16_t, debugger seperti GDB lebih mudah menampilkannya sebagai data karakter - Nama tipe resmi Win32 adalah
wchar_t, tetapi penulisan yang secara eksplisit menyatakan UTF-16 lebih disukai
- Bila berbasis
u8digunakan untuk octet dan terutama data UTF-8, sedangkanbytedibedakan untuk memori mentah dan aliasing type khusus- Kekhawatiran terhadap sistem yang tidak mendukung tipe fixed-width dianggap tidak terlalu praktis
- Nama tipe panjang seperti
int_fast32_tjuga dianggap pemborosan yang tidak perlu
- Nama tipe panjang seperti
- Saat hanya menampilkan potongan kode secara terpisah, alias ini tidak dipakai sendiri
- Karena pembaca juga memerlukan
typedefuntuk memahami konteksnya
- Karena pembaca juga memerlukan
Aturan makro dan assert
- Makro bergaya fungsi menggunakan huruf kecil
- Contoh:
countof(a),lengthof(s),new(a, t, n)
- Contoh:
- Untuk konstanta tetap lebih disukai
ALL_CAPS, tetapi makro bergaya fungsi dianggap lebih enak dibaca dalam huruf kecil - Makro bergaya fungsi juga memiliki masalah namespace yang lebih kecil daripada makro biasa
- Makro
new()dan variabel·fieldnewbisa ada bersamaan - Karena hanya diperluas sebagai makro bila berbentuk pemanggilan fungsi
- Makro
- Makro
assertuntuk GCC dan Clang menggunakan bentukwhile (!(c)) __builtin_unreachable() - Cara assert ini tidak memerlukan pemisahan konfigurasi build
- Tidak perlu definisi terpisah untuk build debug dan rilis
- Apakah ia aktif atau tidak dikendalikan oleh keberadaan Undefined Behavior Sanitizer, yaitu UBSan
libubsanmenyediakan keluaran diagnostik yang mencakup nama file dan nomor baris- Dalam build rilis, ini menjadi petunjuk optimisasi yang praktis
- Untuk mengaktifkan assertion di build rilis, gunakan mode trap UBSan dengan
-fsanitize-trapdan aktifkan setidaknya-fsanitize=unreachable - Secara teori
-funreachable-trapsjuga bisa, tetapi pada saat penulisan, beberapa rilis GCC terbaru sedang rusak
Hal-hal yang dikurangi dalam deklarasi
consttidak digunakan pada parameter- Dianggap tidak punya peran praktis dalam optimisasi
- Disebut sulit mengingat kasus nyata ketika itu menangkap kesalahan atau akan menangkap kesalahan
- Nama parameter yang baik dianggap sudah cukup sebagai dokumentasi prototipe
- Penghapusan
constadalah perubahan yang meningkatkan produktivitas dengan mengurangi beban kognitif dan noise visual - Sebagai pengecualian kecil,
consttetap disukai sebagai petunjuk untuk menempatkan tabel statis ke memori read-only dekat kode- Jika perlu,
constdihilangkan lewat cast
- Jika perlu,
- Untuk null pointer, digunakan literal
0- Ini adalah gaya yang sudah dipakai sekitar 7 tahun
- Meski ada kemungkinan cacat teoretis, tidak ada kejadian nyata yang terlihat dalam ratusan ribu baris kode
restricthanya dipakai saat diperlukan- Kode disusun misalnya dengan tidak memakai parameter out di dalam loop, atau dengan menghindari parameter out sejak awal
inlinetidak digunakan- Karena semuanya dikompilasi sebagai satu unit translasi
- Semua struct di-
typedef- Menghapus keyword
structmembuat kode lebih mudah dibaca - Untuk struct rekursif, forward declaration diletakkan tepat di atasnya, dan field menggunakan nama pendek
- Menghapus keyword
- Semua fungsi selain entry point dideklarasikan sebagai
static- Karena diasumsikan kompilasi unit translasi tunggal
- Berkat nama tipe pendek, penghapusan
const, dan penghapusanstruct, tipe kembalian fungsi dan nama fungsi bisa diletakkan nyaman pada baris yang sama - Pernah ada masa nama tipe ditulis dengan huruf besar, tetapi akhirnya ditinggalkan
String memakai s8 alih-alih null-terminated
- Salah satu perubahan paling produktif adalah menolak sepenuhnya string null-terminated dan menggunakan tipe string
s8yang memilikidatadanlen - Struktur
s8:u8 *datasize len
- Makro
s8(s)membungkus literal string C menjadi strings8 s8diteruskan dan dikembalikan sebagai nilai seperti fat pointers8juga cocok dipakai sebagai prefiks fungsi- Karena nama keluarga
strsudah direservasi - Contoh:
s8span,s8equals,s8compare,s8hash,s8trim,s8clone
- Karena nama keluarga
- Untuk membandingkan literal, digunakan bentuk seperti
s8equals(tagname, s8("body")) - Pernah dicoba juga cara mengikat ukuran dan array dalam satu alokasi dengan flexible array member, tetapi dianggap kurang fleksibel sehingga kekurangannya lebih besar daripada kelebihannya
- Ada juga kasus ketika sempat mengira program sederhana tidak memerlukan tipe string, tetapi kebanyakan ternyata penilaian itu keliru
s16juga digunakan sebagai tipe pendukung UTF-16- Memiliki
c16 *datadansize len - Soal cara menambahkan
upada literal di makro masih belum sepenuhnya meyakinkan
- Memiliki
Pengembalian struct dan cara inisialisasi
- Pengembalian struct lebih disukai daripada parameter out
- Secara praktis ini adalah cara mengembalikan beberapa nilai, walau tanpa destructuring
- Contoh
i32parse(s8)mengembalikan hasil parsingvaluedan statusoksekaligus - Biaya salinan tambahan dianggap bukan masalah besar dalam praktik
- Karena calling convention dapat mengubahnya menjadi parameter out
restricttersembunyi - Atau jika di-inline, overhead nilai kembalian menjadi tidak berarti
- Karena calling convention dapat mengubahnya menjadi parameter out
- Pendekatan ini mengurangi godaan untuk menandai error dengan sinyal in-band seperti nilai null khusus
- Disukai pola membuat nilai kembalian yang diinisialisasi nol di awal fungsi lalu memakainya untuk semua
return- Saat error, fungsi langsung mengembalikan keadaan nol tersebut
- Pada jalur sukses,
okdiset ke true tepat sebelumreturn
- Selain data statis dan makro
s8·s16, penggunaan initializer juga dikurangi- Designated initializer pun dihindari, dan inisialisasi dilakukan lewat assignment
- Inisialisasi dengan assignment dianggap mudah dibaca, dan di antara tiap assignment ada sequence point yang memberi urutan eksplisit
- Pada inisialisasi yang hasilnya bisa dipengaruhi urutan pemanggilan, seperti fungsi pembangkit bilangan acak, jadi tidak perlu memikirkan kemungkinan nilai yang mungkin muncul
Deklarasi Win32 dan inline assembly
__attribute__kurang disukai dibanding__attribute- Sufiks
__di belakang dianggap berlebihan dan tidak perlu
- Sufiks
- Dalam pemrograman sistem Win32,
windows.htidak di-include; prototipe yang dibutuhkan ditulis langsung- Karena biasanya jumlah deklarasi dan definisi yang diperlukan tidak banyak
- Ini mengurangi waktu build dan membuat namespace tidak terlalu berantakan
- Juga lebih cocok dipadukan dengan tipe kustom yang lebih rapi seperti
u32,b32,uptrdaripadaDWORD,BOOL,ULONG_PTR
- Contoh deklarasi Win32 memakai makro
W32(r) __declspec(dllimport) r __stdcall- Fungsi seperti
ExitProcess,GetStdHandle,VirtualAlloc,WriteConsoleA,WriteConsoleWdideklarasikan langsung
- Fungsi seperti
- Dalam inline assembly, tanda kurung luar diperlakukan seperti kurung kurawal
- Seperti pada
if, diberi spasi sebelum tanda kurung buka - Tiap baris constraint dimulai dengan titik dua
- Seperti pada
- Contoh kecil untuk melihat gaya yang disebutkan tersedia di
wordhist.c - Contoh yang sedikit lebih besar adalah implementasi bahasa pemrograman mini
asmint.c
1 komentar
Pendapat Hacker News
Tampaknya mereka menganggap
#define sizeof(x) (size)sizeof(x)tidak perlu tanda kurung luar, tetapi ada satu pengecualian yang sangat kecilCasting memiliki prioritas lebih tinggi daripada perkalian, jadi
sizeof(x) * 3berjalan aman sebagai(size)sizeof(x) * 3Namun pada
(size)sizeof(x)[y], array indexing diterapkan lebih dulu daripada casting, sehingga menjadi(size)(sizeof(x)[y]), bukan((size)sizeof(x))[y]Dalam kode nyata, hampir tidak ada alasan untuk melakukan indexing pada
sizeof(x), tetapi karena C mengizinkaninteger[pointer]bermakna sama denganpointer[integer], makro ini bisa tetap terkompilasi namun bekerja keliru karena kurang tanda kurungYang lebih mendasar, saya juga sulit setuju dengan klaim bahwa signed size lebih baik. Penulis mengatakan unsigned size adalah sumber cacat, tetapi kode yang diberikan juga punya bug yang merusak memori jika
countbernilai negatifPada integer tanpa tanda, jumlah negatif tidak bisa direpresentasikan, dan jika terjadi overflow nilainya menjadi bilangan positif yang sangat besar sehingga tertangkap oleh pemeriksaan yang ada. Secara pribadi, saya lebih suka memakai integer tanpa tanda, tetapi sebisa mungkin menggunakan wrapper pemeriksa rentang yang menghentikan program saat overflow
_BoolKarena ekspresi yang bekerja baik di
if (flags & FLAG_ALLOCATED)bisa diekstrak menjadi variabel boolean seperti_Bool need_free = flags & FLAG_ALLOCATED;flags & FLAG_ALLOCATEDsaat disetel bisa bernilai sembarang nilai non-nol, bukan 1, dan_Boolmenormalkannya menjadi 1. Jika ditampung sebagaiint,if (need_free)akan lolos, tetapiif (need_free == true)bisa gagalAda juga kekurangannya. Saat refactoring, jika melewatkan fakta bahwa konversi implisit ke
_Boolsebelumnya melakukan sesuatu yang berguna, kode bisa berubah menjadi kode keliru sepertiif ((flags & FLAG_ALLOCATED) == true)Selain itu, saat membaca struct dari disk atau mengisi byte sembarang, jika field
_Boolbukan 0 atau 1, ada risiko undefined behavior(size)(sizeof(x)[y])pun mungkin mengejutkan banyak orang, tetapi itu sama dengan(size)(sizeof ((x)[y]))sizeofbukan fungsi, melainkan operator unary, dan indexing serta pemanggilan fungsi punya prioritas lebih tinggi daripadasizeof. Karena itu saya lebih suka memberi spasi setelahsizeof, dan memakai tanda kurung pada operand hanya saat diperlukanhttps://en.cppreference.com/w/c/language/operator_precedence
Jika ingin menulis makro dengan benar, bentuknya menjadi
#define sizeof(x) ((size)(sizeof (x)))Mendefinisikan tipe sendiri rasanya sudah satu langkah terlalu jauh
Bahkan orang yang sudah terbiasa dengan tipe C tetap harus mempelajari sistem aneh tersendiri untuk memahami satu program. Menentukan ukuran memang masuk akal, jadi penggunaan
uint32_talih-alihuintbisa dimengertiTipe semacam ini seharusnya didefinisikan di header yang tepat, dan mungkin saya salah karena sudah lama tidak memakai C
intdi C adalah 32-bitMemang tidak pada target 16-bit, tetapi apakah Anda benar-benar akan mem-porting program 5MB ke 16-bit? Kekhawatiran seperti itu biasanya tidak bernilai
Masalahnya adalah
long. Di sebagian mesin 32-bit, di sebagian lain 64-bit, jadi membingungkan. Untungnyalong longselalu 64-bit, jadi cukup tinggalkanlongchar8-bit,short16-bit,int32-bit,long long64-bit, selesai. Di C, kita sudah membuang waktu tanpa henti untuk ukuranintBagi orang yang sering memakai C, singkatan-singkatan di sini akrab, dan untuk sebuah sistem tipe kustom, ini cukup elegan. Mengingatkan pada Rust
stdint.hSaya selalu heran melihat banyak proyek bersusah payah membuat ulang file ini
Menerjemahkan ulang tipe standar dengan nama sendiri merepotkan pembaca. Dulu di sebuah proyek C++, saya pernah bertanya mengapa ada begitu banyak
typedefuntuk koleksi, referensi, dan objek majemuk, lalu dijawab bahwa itu membuatnya lebih mudah dipahamiBelakangan saya melihat ada cheatsheet typedef tertempel di samping monitor orang itu
Sering terlihat tipe seperti
dim_t, yang menjadi 32-bit atau 64-bit tergantung penggunaan. Bahkan di platform 64-bit, struktur dengan pointer compression sering memakai integer 32-bitMisalnya, jika mengalokasikan heap sendiri dan hanya menyimpan offset 32-bit, untuk beban kerja di bawah 4GB penggunaan memori bisa berkurang setengah, dan cache locality juga membaik sehingga performa meningkat
Meninggalkan konvensi C yang sudah mapan hanya karena preferensi pribadi rasanya agak berlebihan
Memakai
u8,i32alih-alihuint8_tatauint32_tmemang mengurangi beberapa karakter, tetapi bisa membingungkan orang lain saat membaca kodeMemakai tipe string kustom alih-alih string berakhiran null juga terasa meningkatkan kesulitan kolaborasi, mengingat C dibangun dengan berpusat pada string semacam itu
Menulis sendiri prototipe Win32 API tanpa menyertakan
windows.hmungkin bisa mengurangi waktu kompilasi, tetapi rasanya seperti memilih jalan setapak di hutan padahal ada jalan raya yang terawat baik. Banyak di antaranya tampak lebih dekat ke preferensi pribadi daripada kode C yang mudah ditangani semua orangu8ataui32bukan soal menghemat jumlah ketikan, melainkan mengurangi beban perseptual saat membacaArgumen “jumlah penekanan tombol” yang selalu muncul dalam debat verbositas versus keringkasan itu sangat cacat. Keyakinan bahwa keringkasan hanya baik untuk mengetik cepat, sedangkan verbositas selalu lebih baik untuk dibaca, itu keliru
Verbositas juga punya kelebihan untuk pemahaman bacaan, tetapi keringkasan juga punya kelebihan, dan tidak ada pihak yang jelas-jelas menang. Keduanya hanyalah kompromi yang berbeda
u16banyak dipakai, dan kecil kemungkinannya membingungkan programmerTitik yang benar-benar runtuh adalah ketika dua program berbeda masing-masing mendefinisikan
u16dan mengeksposnya di file header, lalu program ketiga menyertakan kedua header itu sekaligusTipe library yang memakai namespace akan berbentuk seperti
libname_u32, dan kalau sudah begitu rasanya lebih ingin memakaiuint32_tsaja daripada prefikslibname_u8ataui32paling-paling hanya teoretis, dan tampak agak seperti strawmanMereka mungkin kesal, tetapi bukan bingung. Seperti kata Rich Hickey, sebelum belajar cara membacanya, semua hal sulit dibaca
Katanya memakai boolean 32-bit mungkin terlihat seperti pemborosan memori bagi pemula; kalau begitu sepertinya saya juga pemula
Saya pernah mendengar beberapa kasus ketika itu tidak lebih buruk daripada bool 8-bit, tetapi tidak melihat kasus ketika itu benar-benar lebih baik. Jika ada boolean yang berdekatan di struct, atau variabel boolean sebuah fungsi terdorong dari register ke stack, tetap saja memori terbuang
Meski hanya beberapa byte, saya tidak mengerti mengapa sengaja melakukan pesimisasi. Apa yang didapat dari memakai ukuran yang lebih besar?
Bentuknya ada nilai kondisi di depan struct per siklus, lalu di belakangnya diikuti 512, 1024, atau 2048 nilai sampel. Seorang junior ingin menghemat ruang, jadi ia mem-packing struct dan membuat nilai kondisi menjadi 8-bit 1 byte
Kode yang “ditingkatkan” itu menurunkan throughput sekitar 10 kali di chip Intel, dan memicu BUS ERROR pada arsitektur SPARC RISC
Karena header struct di-packing, array data menjadi tidak selaras; Intel diam-diam harus mengambil dua word 32-bit dan menggabungkannya, sedangkan SPARC marah secara wajar terhadap data yang tidak selaras
Jika itu komputasi pipeline yang mementingkan throughput, bukan penyimpanan file jangka panjang, terkadang lebih baik menyesuaikan data dengan alignment arsitektur daripada mem-packing-nya demi “menghemat ruang”
Hampir semua compiler melakukannya, jadi cukup cari “structure alignment/padding”. Jika compiler toh akan menyisakan ruang kosong, lebih baik memakai memori itu sendiri; jika tidak, Anda bisa kehilangan performa
Lebih tepatnya, setiap field harus berada pada alamat yang habis dibagi ukuran dirinya atau ukuran wordline, dan keseluruhan struct juga harus di-padding menjadi kelipatan ukuran field terbesar. Dalam praktiknya, biasanya ini berarti alignment 32-bit
Referensi: http://www.catb.org/esr/structure-packing/
boolyang sebenarnya, sanitizer akan memberi peringatan ketika nilainya bukan 0 untukfalseatau 1 untuktrueSaya tidak setuju dengan klaim soal pengembalian struct dan parameter output
Itu membuat fungsi yang bisa mengembalikan error jauh lebih sulit dikomposisikan, dan tipe bertambah di mana-mana. Dalam praktiknya hampir semua fungsi bisa gagal, jadi gaya pengembalian error yang dapat diprediksi lebih penting, terutama jika sampai menangani kehabisan memori
Itu sangat sulit dan manfaatnya juga hampir tidak ada. Pada titik itu, masalah yang muncul jauh berbeda daripada pilihan gaya pemrograman
errnobiasa dan parameter output, tetapi C tidak memilikinyaMeski begitu, mengomposisikan nilai opsional di C memang selalu agak menyakitkan. Jika tidak memakai exception, di banyak bahasa exception dan monad tampak seperti dua pilihan utama, tetapi keduanya tidak cocok di C dan juga tidak cocok dengan filosofi sebagian besar programmer C
Untuk pemanggilan satu-ke-satu yang sederhana, makro bisa dicoba, tetapi ada batasnya. Meski C++ mengerikan, C++ optional lebih menyenangkan dipakai daripada
if(foo(x,y, out1, out2) != WHATEVER_LIBRARY_OK) { ... }Pola menambahkan
if (thing(...)) goto failpada setiap pemanggilan fungsi juga tidak tampak terlalu bagus, meski pihak Go tampaknya menyukainyaAtau ada
thread_local mylibrary_errno, yang di dalam library mungkin memang cara yang tepat, lalu di batasnya bisa dikonversi menjadi nilai balik enumSaat membaca sampai bagian “signed sizes are the way”, rasanya cukup berhenti di situ saja
signed size adalah kebocoran abstraksi yang sangat mengejutkan dan cara yang mengundang bencana
Pernyataan bahwa
consttidak punya peran praktis dan tidak pernah membantu menangkap kesalahan juga sulit diterima. Orang sering tertukar antara buffer input dan buffer output, danconstlangsung menampakkannyaAnjuran agar semua fungsi selain entry point dibuat
staticjuga bisa membuat kita mengutuk penulisnya saat debugging karena tidak bisa menemukan variabel atau fungsiPreferensi mengembalikan struct rentan membuat orang tanpa sengaja mengembalikan pointer stack dan membuka celah keamanan besar. Jika meneruskan buffer output, semantik kepemilikan jadi jelas
Saran ini mungkin cukup cocok bagi orang yang terutama menulis kode sistem 64-bit, tetapi di ranah embedded 32-bit bisa cepat menjadi masalah
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p14...
consttidak akan pernah puas, jadi pakai sajaconstdi tempat yang perlu, propagasikan seperlunya, lalu abaikan keluhannyaKalau mereka menghapusnya, masukkan lagi. Selalu pihak mereka yang lebih dulu lelah. Sudah 25 tahun saya melakukan ini dan masih bertahan
staticbisa bergantung pada tool. Sekitar 15 tahun lalu saya beralih ke defaultstaticdan penggunaansize_tsecara menyeluruh, dan sejauh ini belum mengalami masalahMenarik bahwa pengalaman saya justru mengarah ke arah lain
https://dlang.org/blog/2023/10/02/crafting-self-evident-code...
Artikelnya berpusat pada D, tetapi prinsipnya juga berlaku untuk C
Bagian tentang memindahkan ekspresi kondisi ke dalam
doX()dandoZ()menarik. Saya tidak tahu apakah itu selalu benar; tergantung di mana abstraksi diletakkan dan model mental terhadap kodenyaMisalnya
deleteRecords();tidak lebih baik daripadaif let x = deadRecords() deleteRecords(x);. Yang terakhir terlihat lebih berantakan, tetapi ada nilainya karena di bagian depan menunjukkan bahwa ini bukan penghapusan, melainkan pemangkasanKalau fungsi diganti dengan cerdas menjadi seperti
pruneDeadProjects(), itu baik-baik saja, tetapi sekadar memindahkan kondisi ke dalam fungsi bisa membuat konteks menjadi berbahaya dan menjadi abstraksi yang bocorSaya setuju memakai
typedefuntuk semua struct karena membantu keringkasanMenurut saya
typedefboleh digunakan cukup banyak. Namun sebaiknya hanyatypedefobjeknya sendiri, bukan pointernya. Jika butuh pointer, kapan pun bisa menulis(type *)Khususnya untuk function pointer, yang harus di-typedef bukan function pointer, melainkan fungsi itu sendiri. Dengan begitu typedef tersebut juga bisa dipakai pada deklarasi fungsi untuk mendapatkan pemeriksaan tipe parameter, dan saat signature fungsi berubah tidak perlu memperbaiki semua deklarasi
Kebanyakan codebase C salah melakukan ini dengan men-typedef function pointer, lalu tetap harus menulis deklarasi fungsi yang disesuaikan dengan definisi pointer itu secara manual
Saya masih belum yakin dengan cara memakai struct sebagai tipe kembalian. Saya lebih suka memakai kode error numerik sebagai nilai kembalian, dan menerima nilai kembalian lainnya melalui parameter output
typedefuntuk meniru kelas yang semua field-nya private, dan memakaistructuntuk struktur data sederhanaKelas seharusnya hanya diakses lewat fungsi, sedangkan struct seharusnya bisa diakses langsung
Ini kurang lebih dekat dengan konvensi standar C/POSIX. Misalnya perbedaan antara
pthread_tdanstruct statHal seperti SDL_net melakukan persis itu, dan saya tidak menyukainya. Sebenarnya pointer, tetapi di-
typedefseolah-olah value typeSaya paham maksudnya, tetapi caranya cukup membuat tidak nyaman
Banyak bagian dari artikel ini masuk akal
Saya mulai menulis bare-metal OS untuk Arm64, dan meski masih tahap awal, saya melakukan hal serupa. Saya memakai string Pascal dan juga mengganti nama tipe. Namun gayanya
int8, bukani8Karena saya cepat memutuskan tidak berniat mem-port software nyata, saya tidak perlu mengikuti fungsi atau konvensi library C standar. Berkat itu saya bisa bereksperimen lebih bebas
C adalah bahasa yang begitu tua sampai beban dari masa ketika setiap byte berharga masih tersisa hingga ke nama fungsi. Senang rasanya bisa lepas dari itu, dan isi artikel ini beserta berbagai perubahan nama kecil terasa seperti perapian yang cukup rapi
typedef float f32;,typedef double f64;tampak seperti pijakan yang berbahaya karena mengasumsikanfloatadalah 32-bit dandoubleadalah 64-bitOpenCV mendefinisikan
float16_t, CUDA mengimplementasikan bilangan floating-point presisi setengah, dan mikrokontroler bisa memiliki implementasinya masing-masingC++23 memperkenalkan tipe floating-point berlebar tetap, tetapi saya tidak tahu cara memaksakannya di C. Tampaknya lebih baik menyediakan makro untuk memeriksa pada waktu kompilasi bahwa tidak ada kehilangan data
Secara keseluruhan, seperti yang dikatakan orang lain, demi keterbacaan mungkin lebih baik membiarkan sebagian hal tetap pada default, meskipun tidak seringkas itu
[0] https://docs.opencv.org/4.x/df/dc9/classcv_1_1float16__t.htm...
[1] https://docs.nvidia.com/cuda/cuda-math-api/group__CUDA__MATH...
[2] https://en.cppreference.com/w/cpp/types/floating-point
_Floattypedef _Float32 f32;typedef _Float64 f64;https://gcc.gnu.org/onlinedocs/gcc/Floating-Types.html