C言語のポインタ変数を含む構造体初期化について


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

構造体を初期化するときの仕様として、  
`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]

よろしくお願いします。




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

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

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

と書かれています。

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

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

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

あと補足

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

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




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

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

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

と書かれています。

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

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

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

あと補足

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

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

