LoginSignup
2
3

More than 5 years have passed since last update.

C言語のポインタを含む構造体の初期化まとめ。

Last updated at Posted at 2017-04-12

C99に準拠した内容です。

C11でも特に変わっていなさそう。
C言語の仕様で次の構造体の初期化はどうなるのか、少しまとめておきたい。

#include<stdio.h>

struct S
{
    int val;
    void *ptr;
    int val2;
};

int main(int argc, char *argv[])
{
    struct S a_var = {0};
    static struct S s_var;

    // 自動変数の表示
    printf("%d\n%d\n", a_var.val, a_var.val2);
    if (a_var.ptr == NULL)
    {
        // NULLのときの処理
    }

    // 静的変数の表示 => 初期化していないので、.bssに置かれる。
    printf("%d\n%d\n", s_var.val, s_var.val2);
    if (s_var.ptr == NULL)
    {
        // NULLのときの処理
    }
    return 0;
}

下記の2ページの内容をまとめてみる。

スタックオーバーフロー:C言語のポインタ変数を含む構造体初期化について
スタックオーバーフロー:how about .bss section not zero initialized

算術型:int / long / char 等

初期化状態 auto / 算術型 static / 算術型 グローバル / 算術型
不定 0 0
初期化値 初期化値 初期化値
初期化状態 auto / ポインタ型 static / ポインタ型 グローバル / ポインタ型
不定 NULL NULL
初期化値 初期化値 初期化値

配列や、構造体の先頭要素のみを明示的に初期化した場合
(上記ソースの「struct S v={0};」みたいなやり方)は
先頭要素以外staticやグローバル変数の未初期化変数と同様の方法で初期化される。

ということで、上記の構造体を利用するコードでは、初期化が完了すると以下の値を持つことになる。

 a_var.val -> 0
 a_var.ptr -> NULL
 a_var.val2 -> 0

 s_var.val -> 0
 s_var.ptr -> NULL
 s_var.val2 -> 0

ちゃんとC99の規格に準拠していれば、NULLは「数値型に変換した時0と一致する」ということなのでC言語で言うところのint型の0とNULLの値は一致しなければならない。

(ただし、C言語のソース上ではその比較はやってはいけない(可読性下がるからマジやめてね)って話と言う認識でいる)

ということは、自作でOS作ってる人はプログラムローダとか作るときは責任持って.bssをゼロ埋めしてあげる必要があるのだなぁ。

間違っても1とかで埋めてはいけない。

[追記]
スタックに格納した変数はコンパイラが0クリアするコードを書いてくれるはずだよ と言うツッコミが有ったので、BinaryNinjaでディスアセンブルしてみる。

image.png

スタックに確保されたやつは赤枠の部分みたいに、代入コードが生成されて初期化されるのを忘れていた。
指摘されて あー そういえば!ってなった。

ちなみに、.bssの方はどうなっているかをobjdumpで見る。

image.png

とりあえずBinaryNinjaでも見てみる。
.bssの初期化値はファイルに書かれて無いはずだけど
(.bssはセクションフラグにLOADが存在しない、ALLOCのみ)
BinaryNinjaが勝手に解釈して勝手にゼロを代入している。
image.png

だからまぁ、ローダー側はC言語の規格に準拠する処理系と言いたいなら、.bssをゼロ埋めしてあげよう。

以上

2
3
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3