質問: 以下のような三行のコードがありました。。。順番は不問です。 ``` #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) struct boot_params boot_params __attribute__((aligned(16))); BUILD_BUG_ON(sizeof boot_params != 4096); ``` 上はマクロ、真ん中は構造体?、下は実際の使用だと思います。 マクロの使い方の`*!!`の部分の意味がわかりません。 真ん中の構造体は`()`が使われている理由がわかりません。そして、`aligned`が何なのか解決できません。 そのため一番下の結果が予測できません。 ファイルは、`/linux-4.5.1/arch/x86/boot`内にあるものです。
回答: 一部だけ。 ### 否定の否定 (`!!`) C言語の`!`演算子などを使いNOT演算(否定)を行なうと対象の真偽を逆転させます。 対象が真と見なせる値であれば真偽値の偽を、偽と見なせる値であれば真偽値の真を返します。 これを`!!`のように2回行うと、逆転させて、また逆転させるので、真偽は元にもどり変わりません。 対象を真偽値にする、という効果だけが得られます。 この機能は、例えばJavaScriptであれば`Boolean()`という風に言語によってより読みやすく書く方法が用意されていますが、短かく書きたい人は常にいます。 C言語の場合、真なら1、偽なら0と、0と1で真偽値を表わしていますから、`!!`を付けると0か1になります。 ### GCC拡張の`__attribute__`に渡す引数をかっこで囲む理由 `__attribute__`はGCC拡張なので他のコンパイラでコンパイルする時は消さなければいけません。 これを自動でやるにはマクロを使います。 例えばこんな風に。 ``` #ifndef __GNUC__ #define __attribute__(x) /* 消す */ #endif ``` この場合`__attribute__`に渡す引数が一つであれば問題ないのですが複数あると、プリプロセスの段階で「引数が多すぎるよ」というエラーになります。 ですから、gccの方で`__attribute__`に渡す引数は()で囲む、というルールにしてしまっています。 こうすれば他のコンパイラからは一つの引数として見なされるからです。 ちなみに、C99以降であれば可変長引数のマクロがありますから、引数がいくつでもエラーを出さず消してくれるマクロを作れます。 ``` #define __attribute__(x, ...) /* 消す */ ```