Konteks
Kami mem-porting kode C yang awalnya dikompilasi menggunakan kompiler C 8-bit untuk mikrokontroler PIC. Ungkapan umum yang digunakan untuk mencegah variabel global yang tidak ditandatangani (misalnya, penghitung kesalahan) berguling kembali ke nol adalah sebagai berikut:
if(~counter) counter++;
Operator bitwise di sini membalikkan semua bit dan pernyataan ini hanya benar jika counter
kurang dari nilai maksimum. Yang penting, ini berfungsi terlepas dari ukuran variabel.
Masalah
Kami sekarang menargetkan prosesor ARM 32-bit menggunakan GCC. Kami memperhatikan bahwa kode yang sama menghasilkan hasil yang berbeda. Sejauh yang kami tahu, sepertinya operasi komplemen bitwise mengembalikan nilai dengan ukuran yang berbeda dari yang kami harapkan. Untuk mereproduksi ini, kami mengkompilasi, di GCC:
uint8_t i = 0;
int sz;
sz = sizeof(i);
printf("Size of variable: %d\n", sz); // Size of variable: 1
sz = sizeof(~i);
printf("Size of result: %d\n", sz); // Size of result: 4
Pada baris pertama output, kita mendapatkan apa yang kita harapkan: i
adalah 1 byte. Namun, komplemen bitwise i
sebenarnya empat byte yang menyebabkan masalah karena perbandingan dengan ini sekarang tidak akan memberikan hasil yang diharapkan. Misalnya, jika melakukan (di mana i
diinisialisasi dengan benar uint8_t
):
if(~i) i++;
Kita akan melihat i
"membungkus" dari 0xFF kembali ke 0x00. Perilaku ini berbeda dalam GCC dibandingkan dengan ketika dulu berfungsi seperti yang kami maksudkan dalam kompilator sebelumnya dan mikrokontroler PIC 8-bit.
Kami menyadari bahwa kami dapat menyelesaikan ini dengan casting seperti:
if((uint8_t)~i) i++;
Atau, oleh
if(i < 0xFF) i++;
Namun dalam kedua penyelesaian ini, ukuran variabel harus diketahui dan rawan kesalahan untuk pengembang perangkat lunak. Pemeriksaan batas atas semacam ini terjadi di seluruh basis kode. Ada beberapa ukuran variabel (mis., uint16_t
Dan unsigned char
lain - lain) dan mengubahnya dalam basis kode yang berfungsi bukan sesuatu yang kami harapkan.
Pertanyaan
Apakah pemahaman kita tentang masalah itu benar, dan apakah ada opsi yang tersedia untuk menyelesaikan ini yang tidak perlu mengunjungi kembali setiap kasus di mana kita telah menggunakan idiom ini? Apakah asumsi kami benar, bahwa operasi seperti pelengkap bitwise harus mengembalikan hasil yang ukurannya sama dengan operan? Sepertinya ini akan pecah, tergantung pada arsitektur prosesor. Saya merasa seperti saya minum pil gila dan C harus sedikit lebih portabel daripada ini. Sekali lagi, pemahaman kita tentang ini bisa salah.
Di permukaan ini mungkin tidak tampak seperti masalah besar tetapi idiom yang sebelumnya berfungsi ini digunakan di ratusan lokasi dan kami ingin memahami ini sebelum melanjutkan dengan perubahan mahal.
Catatan: Ada pertanyaan duplikat yang tampaknya serupa tetapi tidak tepat di sini: Operasi bitwise pada char memberikan hasil 32 bit
Saya tidak melihat inti sebenarnya dari masalah yang dibahas di sana, yaitu, ukuran hasil komplemen bitwise menjadi berbeda dari apa yang diteruskan ke operator.