Linux Kernelコードアート-コンパイル時に断言

3472 ワード

このシリーズの文章は主に私がLinuxカーネルを読む过程の中で、関心の比较的に理解しにくいがまた巧みなコードの断片(OSの各モジュールの设计思想に関心を持たないで、この部分は私は“Linux Kernelを深く理解する”シリーズの文章の中で书くつもりです)を书いて、1つはカーネルコードを通じてC言语とアセンブリ言语の文法を复习します二カーネル開発の大牛たちがコードを書くスタイルと構想を学ぶ.
カーネルファイルinclude/linux/bug.hには、次の2行のマクロ定義があります.





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が0であるかどうかを確認し、0でコンパイルされ、0を返します.0でない場合、コンパイルはパスしません.
このマクロの名前からして勘違いしやすいのか、「BUILD_BUG_OR_ZERO」に変更した方が良いのか、このpatch(http://lkml.indiana.edu/hypermail/linux/kernel/0703.1/1546.html)が、コミュニティに受け入れられなかった.このマクロ定義の名前にかかわらず、このマクロがどのように実現されているかを徐々に分析します.
  sizeof(struct { int : –!!(e); } ))
1.(e):式eの宣言
2. !!(e):eの結果を2回非を求める.すなわち、eの開始が0であれば、結果は0である.eが0でない場合、結果は1になります.
3. –!!(e):さらに-1を乗じる.ステップ2の結果が0の場合、0のままです.そうでない場合、結果は-1です.
4. struct { int : –!!(0); }  -->  struct { int : 0; } : eの結果が0である場合、構造体はint型のデータドメインを有し、その占めるビットの個数を0とすることを宣言する.これは何の問題もありません.私たちはすべて正常だと思います.
5. struct { int : –!!(1); }  -->  struct { int : –1; } : eの結果が0でない場合、構造体のint型データドメインのビットドメインが負になり、ビットドメインが負に宣言されます.これは構文のエラーです.
6.ビットドメインが0であることを宣言した構造体の結果か、ビットドメインが負の数のコンパイルエラーが発生した.正しくコンパイルできたら、構造体をsizeof操作してsize_というタイプを得ます.tの結果、値は0です.
まとめてみると、BUILD_BUG_ON_ZERO(e)は、式eの結果が0であればコンパイルが通過し、そのマクロの値も0であることを示す.式eの結果が0でない場合、コンパイルは通過しません.
これはC言語のassertマクロの使い方を連想させます.
  void assert(int expression);
パラメータexpression計算の結果が0の場合、stderrにエラー情報を印刷し、abortを呼び出してプログラムの実行を終了します.そうでなければ断言が成立し、実行を継続します.
私たちが議論しているマクロとassertの本質的な違いは、私たちのマクロはコンパイル時にテストされ、assertマクロは実行時にテストされることです.実行時に遅らせるのではなく、コンパイル時のエラーをできるだけ早くキャプチャしたいと考えています.このマクロの使い方を「コンパイル時断言」、assertは「実行時断言」と言います.
上を理解してから、2番目のBUILDを見てみましょうBUG_ON_NULL(e)マクロは、最初と同様に、コンパイル時にeがNULLであるかどうかを断言するために使用され、このマクロが0(すなわち、NULLと、最初のマクロとの違い)を返す場合に使用される.NULLでない場合のコンパイルエラー.
上の2つのコンパイル時の断言を除いて、include/linux/bug.hファイルには、次のような意味を考えることができます.
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))   

#define BUILD_BUG_ON_NOT_POWER_OF_2(n)            \ 
    BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))

 
意味は、ファイル内のマクロ定義のコメントの説明を参照してください.
 
----------------------------------------------------------------------------------------
 
参考資料:
http://blog.csdn.net/jiyucn/article/details/862085C言語における構造体位ドメインの詳細説明
http://blog.csdn.net/jiyucn/article/details/862062C言語におけるsizeofに関する問題
http://www.cplusplus.com/reference/cassert/assert/assert用法説明
http://stackoverflow.com/questions/9229601/what-is-in-c-code問題と解答はすべてStackoverflowに由来します