33827


掲題の質問です。まだ仕様を完全に理解したわけではないので違う場合はお手数ですが指摘願います。

構造体を初期化するときの仕様として、  
`struct S v={0};`はメンバ全部初期化されることが保証されてます。  
また、`NULL`は0以外でもよくて100でもいい。  
ただし他の関数や変数とぶつかってはならない。  
ただし、数値型に変換するときは0でなければならない。

そのとき、初期化した構造体に含まれるポインタ変数の値と`NULL`を比較したときにどのようなコンパイラでコンパイルしたとしても、一致しますか？  
また、他のメンバ変数はその場合、ゼロクリアされていることが保証されますか？

[code]

    struct S {
     int val;
     void *ptr;
     int val2;
    }
    
    int main(int argc,char *argv[]){
     struct S v={0};
     printf("%d\n%d\n",v.val,v.val2);
     if( v.ptr == NULL) {
         // NULLのときの処理
     }
    }
    
[/code]

よろしくお願いします。


CC BY-SA 3.0
2017-04-06T23:33:33.347
33824
2017-07-21T09:18:25.800
2017-04-07T03:59:57.330
13886
13886
question
c
C言語のポインタ変数を含む構造体初期化について


`0`で初期化される仕様なので、`NULL`にならないだけでは？


CC BY-SA 3.0
2017-04-07T00:18:53.707
33826
2017-04-07T00:18:53.707
4236
33824
answer


[c](/questions/tagged/c "'c' のタグが付いた質問を表示") 言語規格書 JIS X 3010:2003 6.7.8 初期化
によると Yes  
この章、長い上に項目分割番号が振っていないので解説しづらいのですが

  * 静的記憶域期間をもつオブジェクトを明示的に初期化しない場合は  
a) ポインタ型の場合、空ポインタに初期化する  
b) 算術型の場合、０に初期化する

  * (明示的初期化であって) 初期化子が少ない場合、その集成体型の残りを、静的記憶域期間をもつオブジェクトと同じ規則で暗黙に初期化する

と書かれています。

提示例は、メンバ `val` に対する初期化子 `0` が明記され、それ以外のメンバに対する初期化子が無いと解釈されるので、上記のとおりとなります。

> どのようなコンパイラでコンパイルしたとしても、

規格に合致していないコンパイラでは No かもしれません。  
まあいまどき規格書無視しているコンパイラはかなりレアだと思いますが皆無ではないでしょう。  
そんな変なコンパイラをプログラマの努力で使うのは労力に引き合わないと思います。

あと補足

> また、NULLは0以外でもよくて100でもいい。

これは機械語になった後の内部表現の話です。  
`memset` 等で強引に記憶域に `0` を書き込んだとき、その値が空ポインタの内部表現に一致するかどうかは規定されていません。  
内部表現に関係なく、ソースコード上では、空ポインタは `NULL` に一致します。


CC BY-SA 3.0
2017-04-07T00:21:27.827
33827
2017-04-07T00:21:27.827
8589
33824
answer


C/C++ のナルポインタの仕様は（個人的な感覚では）病的なところがあります。  
null pointer constant
はソース上の表現で、例えば整定数0（コンパイル時に0と定まる整数型式）があります。これがポインタがあるべき場所にあったり、ポインタに変換されると、コンパイラはそれをナルポインタと認識します。  
null pointer
はナルポインタの内部表現のことで、この値がオールビット0であることは保障されていません。他のオブジェクトや関数の参照と異なった値であることが保障されているだけです。  
NULL マクロは null pointer constant を表すマクロなので、null pointer が0でない場合も整定数 0
に展開されることになります。  
C言語では NULL は((void*)0) （これもCのnull pointer
constant）に展開されることも多いですが、C++ではこの展開は行われません。C++では（void*)型のポインタを他の型のポインタに変換するときは明示的なキャストが必要になったからです。C++ではnullptrを使うべきでしょう。

で、質問の答えは  
if( v.ptr == NULL)  
は、たとえnull pointer が0でない処理系でも正しく動作します。  
if( v.ptr == 0)  
でさえ、正しく動作することに注意してください。null pointer （内部表現）が0でなくともこれはv.ptr
がナルポインタのときに真となるのが仕様です。  
他のメンバーは正しく0初期化されます。

ただし、memsetで構造体をオールビット0にする、などの場合は逆に保証されません。

とはいえ、null pointer が0でない処理系などお目にかかったことがないので、これを理解してもなかなか使い所がないのですが。


CC BY-SA 3.0
2017-07-21T09:18:25.800
36564
2017-07-21T09:18:25.800
24517
33824
answer