24172


以下のような三行のコードがありました。。。順番は不問です。

[code]

    #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);
    
[/code]

上はマクロ、真ん中は構造体？、下は実際の使用だと思います。

マクロの使い方の`*!!`の部分の意味がわかりません。  
真ん中の構造体は`()`が使われている理由がわかりません。そして、`aligned`が何なのか解決できません。  
そのため一番下の結果が予測できません。  
ファイルは、`/linux-4.5.1/arch/x86/boot`内にあるものです。


CC BY-SA 3.0
2016-04-20T02:05:31.387
24169
2016-04-20T03:46:05.370
10455
question
linux c アルゴリズム
リナックスのはじめの方のコードでつまずきました。


  1. `#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))`  
conditionが0以外だったらコンパイルエラーにする。  
`!`は単に論理否定で、二つ続けて`!!`とすることで、肯定論理にしています。conditionの値がたとえ10でも論理結果(0 or 1)を返します。  
`char[1 - 2*!!(condition)]`はconditionが0以外だったら
char[-1]になりコンパイルエラーになります。`*`は単なる掛け算です。  
sizeofをとっているのは式にしたいためです。  
式の結果は求めていないのでvoidにキャストしています。

  2. `struct boot_params boot_params __attribute__((aligned(16)));`  
boot_paramsを16byteアライメントに配置する  
`__attribute__((aligned(16)))`はGCCの拡張でC標準ではありませんが、メモリ配置を指定するものです。(
)がやたら多いのは、そういう仕様としか言えません。こちらhttps://gcc.gnu.org/onlinedocs/gcc-5.3.0/gcc/Variable-
Attributes.html を参考にしてください。

  3. `BUILD_BUG_ON(sizeof boot_params != 4096)`  
`sizeof boot_params`が4096でなかったらコンパイルエラーにする。


CC BY-SA 3.0
2016-04-20T02:59:52.587
24172
2016-04-20T03:22:58.440
2016-04-20T03:22:58.440
7844
7844
24169
answer


一部だけ。

### 否定の否定 (`!!`)

C言語の`!`演算子などを使いNOT演算（否定）を行なうと対象の真偽を逆転させます。  
対象が真と見なせる値であれば真偽値の偽を、偽と見なせる値であれば真偽値の真を返します。  
これを`!!`のように2回行うと、逆転させて、また逆転させるので、真偽は元にもどり変わりません。  
対象を真偽値にする、という効果だけが得られます。  
この機能は、例えばJavaScriptであれば`Boolean()`という風に言語によってより読みやすく書く方法が用意されていますが、短かく書きたい人は常にいます。

C言語の場合、真なら1、偽なら0と、0と1で真偽値を表わしていますから、`!!`を付けると0か1になります。

### GCC拡張の`__attribute__`に渡す引数をかっこで囲む理由

`__attribute__`はGCC拡張なので他のコンパイラでコンパイルする時は消さなければいけません。  
これを自動でやるにはマクロを使います。  
例えばこんな風に。

[code]

    #ifndef __GNUC__
    #define __attribute__(x) /* 消す */
    #endif
    
[/code]

この場合`__attribute__`に渡す引数が一つであれば問題ないのですが複数あると、プリプロセスの段階で「引数が多すぎるよ」というエラーになります。  
ですから、gccの方で`__attribute__`に渡す引数は()で囲む、というルールにしてしまっています。  
こうすれば他のコンパイラからは一つの引数として見なされるからです。

ちなみに、C99以降であれば可変長引数のマクロがありますから、引数がいくつでもエラーを出さず消してくれるマクロを作れます。

[code]

    #define __attribute__(x, ...) /* 消す */
    
[/code]


CC BY-SA 3.0
2016-04-20T03:46:05.370
24174
2016-04-20T03:46:05.370
3054
24169
answer