LinuxカーネルにあるBUILD_BUG_ONマクロ。名前からやりたいことは十分に分かるんだけど、これはどういう仕組みなのかというところ。
使っている例としてarch/x86/kernel/head64.cにあるx86_64_start_kernel()を見てみるとこんな感じ。
140 asmlinkage void __init x86_64_start_kernel(char * real_mode_data) 141 { 142 int i; 143 144 /* 145 * Build-time sanity checks on the kernel image and module 146 * area mappings. (these are purely build-time and produce no code) 147 */ 148 BUILD_BUG_ON(MODULES_VADDR < __START_KERNEL_map); 149 BUILD_BUG_ON(MODULES_VADDR - __START_KERNEL_map < KERNEL_IMAGE_SIZE); 150 BUILD_BUG_ON(MODULES_LEN + KERNEL_IMAGE_SIZE > 2*PUD_SIZE); 151 BUILD_BUG_ON((__START_KERNEL_map & ~PMD_MASK) != 0); 152 BUILD_BUG_ON((MODULES_VADDR & ~PMD_MASK) != 0); 153 BUILD_BUG_ON(!(MODULES_VADDR > __START_KERNEL)); 154 BUILD_BUG_ON(!(((MODULES_END - 1) & PGDIR_MASK) == 155 (__START_KERNEL & PGDIR_MASK))); 156 BUILD_BUG_ON(__fix_to_virt(__end_of_fixed_addresses) <= MODULES_END);
BUILD_BUG_ONマクロの実装はinclude/linux/genl_magic_func.hにあり、渡された条件をBUILD_BUG_ON_ZEROマクロにそのまま渡すだけ。
134 #ifndef BUILD_BUG_ON 135 /* Force a compilation error if condition is true */ 136 #define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition)) 137 /* Force a compilation error if condition is true, but also produce a 138 result (of value 0 and type size_t), so the expression can be used 139 e.g. in a structure initializer (or where-ever else comma expressions 140 aren't permitted). */ 141 #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) 142 #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); })) 143 #endif
ということで、BUILD_BUG_ON_ZEROを見ると、構造体をsizeofするという感じですね。
この構造体はメンバ変数にビットフィールドを使っていて評価結果が1の場合、ビットフィールドに指定する数値が-1となりコンパイラエラーになるという算段です。
ここでsizeofをしているのは単に構造体の定義をここでしたいからということでしょうね。
実際に簡単にテストをしてみる。まずはこんなファイルを。
#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition)) #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) int main(int argc, char **argv) { BUILD_BUG_ON(1 == 1); return 0; }
プリプロセッサだけ展開してみる。
masami@saga:~$ gcc -E test.c # 1 "test.c" # 1 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 1 "<command-line>" 2 # 1 "test.c" int main(int argc, char **argv) { ((void)(sizeof(struct { int:-!!(1 == 1); }))); return 0; }
この場合は(1 == 1)の結果は1になるのでint:-1とされてコンパイルエラーになる
実際にコンパイルしてみる。
masami@saga:~$ gcc test.c test.c: In function ‘main’: test.c:2:45: error: negative width in bit-field ‘<anonymous>’ #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) ^ test.c:1:40: note: in expansion of macro ‘BUILD_BUG_ON_ZERO’ #define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition)) ^ test.c:7:2: note: in expansion of macro ‘BUILD_BUG_ON’ BUILD_BUG_ON(1 == 1); ^
(´-`).。oO(よく考えるもんだな~
リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)
- 作者: Dustin Boswell,Trevor Foucher,須藤功平,角征典
- 出版社/メーカー: オライリージャパン
- 発売日: 2012/06/23
- メディア: 単行本(ソフトカバー)
- 購入: 68人 クリック: 1,802回
- この商品を含むブログ (105件) を見る