stdio.h を削除すると、おそらく出力がより意味のあるものになります。内部変数が含まれているため、そのライブラリを無視しましょう。
特定のケースでは、次のことが起こります。
int uninit_global_var;
これはファイルスコープで割り当てられた変数であるため、として宣言された変数と同様に、静的ストレージ期間static
があります。C 標準では、この場合のように、静的ストレージ期間を持つ変数がプログラマーによって明示的に初期化されていない場合、プログラムを開始する前にゼロに設定する必要があります。そのような変数はすべて.bss
セグメントに入れられます。
int init_global_var=5;
この変数はファイル スコープでも割り当てられるため、静的な保存期間もあります。ただし、この場合、プログラマによって初期化されます。C 標準では、プログラムを開始する前に、そのような変数を指定された値に設定する必要があります。このような変数は.data
セグメントに配置されます。
int local_var;
この変数には、自動保存期間 (ローカル) があります。この変数は目的を果たさないため、コンパイラはおそらくこの変数を最適化して取り除きます。しかし、そのような最適化が行われないと仮定しましょう。変数は、それが存在するスコープ (ブロック) が実行されるときに実行時に割り当てられ、そのスコープが終了すると (スコープ外になる) 存在しなくなります。スタックまたは CPU レジスタに割り当てられます。つまり、リンク時に、この変数はプログラム コードとしてのみ存在し、「スタックに int をプッシュ」し、後で「スタックから int をポップ」するアセンブラ命令の形式で存在します。
これらの異なる種類の変数がどのように初期化されるかは、システムによって異なります。ただし、通常、main が呼び出される前に、コンパイラによって挿入されるコードがいくつかあります。これは単純化しすぎていますが、教育学のために、プログラムは実際には次のようになっていると想像できます。
bss
{
int uninit_global_var;
}
data
{
int init_global_var;
}
rodata
{
5;
}
int start_of_program (void) // called by OS
{
memset(bss, 0, bss_size);
memcpy(data, rodata, data_size);
return main();
}
データ:4 bss:4
真の不揮発性メモリを備えた組み込みシステムは上記のコードとまったく同じように動作しますが、RAM ベースのシステムはデータの初期化部分を異なる方法で解決する場合があります。bss はすべてのシステムで同じように機能します。
次のプログラムを実行すると、それらが異なるセグメントに格納されていることを簡単に確認できます。
char uninit1;
char uninit2;
char init1 = 1;
char init2 = 2;
int main (void)
{
char local1 = 1;
char local2 = 2;
printf("bss\t%p\t%p\n", &uninit1, &uninit2);
printf("data\t%p\t%p\n", &init1, &init2);
printf("auto\t%p\t%p\n", &local1, &local2);
}
「uninit」変数が隣接するアドレスに割り当てられていることがわかりますが、他の変数とは異なるアドレスにあります。「init」変数と同じです。「ローカル」変数はどこにでも割り当てることができるため、これら2つの結果として、あらゆる種類の奇妙なアドレスを取得できます。