Linux Kernel, QEMU, and RISC-V
Linux Kernel: BUILD_BUG_ON_ZERO() / BUILD_BUG_ON_NULL()
之前在 trace Linux Kernel source codes 時發現了兩個很特別的 macros:BUILD_BUG_ON_ZERO() 和 BUILD_BUG_ON_NULL() (定義在:include/linux/kernel.h) 它們的定義如下: 1 2 3 4 5 6 /* Force a compilation error if condition is true, but also produce a result (of value 0 and type size_t), so the expression can be used e.g. in a structure initializer (or where-ever else comma expressions aren't permitted). */ #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); })) 其中 e 是我們所傳入的判斷式,若判斷式為 true,則會造成 compile error。如此我們便可透過這個 macro 來判斷是否某些錯誤/不應發生的情況 (判斷式) 是否會發生,若會發生則可在 compile-time 的時候就顯示錯誤訊息。 ...
Linux Kernel: ARRAY_SIZE()
通常我們在 C 語言中取得陣列的元數個數可以透過下列的方式來計算: 1 2 3 4 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) int arr[10]; int arr_size = ARRAY_SIZE(arr); 但如同 Jserv 大大在 這篇文章 中所提到:ARRAY_SIZE() 這樣的 macro 其實是陷阱重重… 因為 macro 本身沒辦法做型態檢查,只是單純的將值帶入並展開,而在 C 中我們常常會將指標和陣列混著使用。因此若是我們將指向該陣列的指標傳入,就會得到錯誤的計算結果。 如下面的程式: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h> #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) int main(void) { int a[10]; int *a_ptr = a; printf("%d\n", ARRAY_SIZE(a)); printf("%d\n", ARRAY_SIZE(a_ptr)); return 0; } 若傳入陣列 a,則結果會正確顯示 size 大小為 10,但若傳入的是指向陣列 a 的指標 a_ptr,則因為指標的在 32 位元作業系統上大小為 4 bytes (4 / 4) 的結果則會變成 1,而並不是我們所要的答案 10。 ...