次のようにCで配列を宣言する場合:
int array[10];
整数の初期値は??コンパイラごとに異なる結果が得られますが、コンパイラまたはOSに関係があるかどうかを知りたいです。
配列が関数で宣言されている場合、値は未定義です。 int x[10];
は、初期化を行わずにmemroyの10-int-size領域の所有権を取得することを意味します。配列がグローバル配列または関数でstatic
として宣言されている場合、すべての要素はまだ初期化されていない場合はゼロに初期化されます。
標準で設定されているように、すべてのグローバルおよび関数の静的変数は自動的に0に初期化されます。自動変数は初期化されません。
int a[10]; // global - all elements are initialised to 0
void foo(void) {
int b[10]; // automatic storage - contain junk
static int c[10]; // static - initialised to 0
}
ただし、ストレージクラスに関係なく、関数変数を常に手動で初期化することをお勧めします。すべての配列要素を0に設定するには、最初の配列項目を0に割り当てるだけです。省略された要素は自動的に0に設定されます。
int b[10] = {0};
auto
ストレージクラス)が初期化されないのはなぜですか?Cはハードウェアに近い。それが最大の強さと最大の危険です。 auto
ストレージクラスオブジェクトがランダムな初期値を持っている理由は、それらがスタックに割り当てられ、自動的にこれらをクリアしないように設計決定が行われたためです(一部、関数呼び出しごとにクリアする必要があるため)。
一方、non _auto
オブジェクトは一度だけクリアする必要があります。さらに、OSはとにかくセキュリティ上の理由で割り当てられたページをクリアする必要があります。したがって、ここでの設計上の決定は、ゼロ初期化を指定することでした。なぜスタックのセキュリティも問題にならないのですか?実際には、最初はクリアされています。表示されるジャンクは、独自のプログラムの呼び出しフレームの以前のインスタンスと、呼び出したライブラリコードからのものです。
最終結果は、高速でメモリ効率の高いコードです。痛みのないアセンブリのすべての利点。 dmrがCを発明する前は、BasicやOSカーネル全体のような「HLL」は、文字通り、巨大なアセンブラープログラムとして実装されていました。 (IBMのような場所では特定の例外があります。)
C規格6.7.8(注10)によると:
自動保存期間を持つオブジェクトが明示的に初期化されていない場合、その値は不定です。
そのため、コンパイラに依存します。 MSVCでは、デバッグビルドは0xccで自動変数を初期化しますが、非デバッグビルドはこれらの変数をまったく初期化しません。
C変数宣言は、メモリの領域を確保して名前を付けるようにコンパイラーに指示するだけです。スタック変数とも呼ばれる自動変数の場合、そのメモリの値は以前の値から変更されません。グローバル変数および静的変数は、プログラムの起動時にゼロに設定されます。
最適化されていないデバッグモードの一部のコンパイラは、自動変数をゼロに設定します。ただし、新しいコンパイラでは、値が既知の不正な値に設定されることが一般的になり、プログラマが無意識のうちにゼロが設定されていることに依存するコードを記述しないようになりました。
コンパイラに配列をゼロに設定するように依頼するには、次のように記述できます。
int array[10] = {0};
さらに良いのは、配列に必要な値を設定することです。これはより効率的で、配列への2回の書き込みを回避します。
ほとんどの最新のコンパイラ(gcc/vc ++など)では、部分的に初期化されたローカル配列/構造体のメンバーは、デフォルトでzero(int)、NULL(char/char string)、0.000000(float/double)に初期化されます。
上記のローカルアレイ/構造データとは別に、static(global/local)およびグローバルスペースメンバーも同じプロパティを維持します。
int a[5] = {0,1,2};
printf("%d %d %d\n",*a, *(a+2), *(a+4));
struct s1
{
int i1;
int i2;
int i3;
char c;
char str[5];
};
struct s1 s11 = {1};
printf("%d %d %d %c %s\n",s11.i1,s11.i2, s11.i3, s11.c, s11.str);
if(!s11.c)
printf("s11.c is null\n");
if(!*(s11.str))
printf("s11.str is null\n");
Gcc/vc ++では、出力は次のようになります。
0 2 0 1 0 0 0.000000 s11.cはnull s11.strはnull
http://www.cplusplus.com/doc/tutorial/arrays/ からのテキスト
概要:
配列の初期化。ローカルスコープの通常の配列(関数内など)を宣言する場合、特に指定しないと、その要素は既定で値に初期化されないため、値を格納するまで内容は不定になります。一方、グローバル配列と静的配列の要素は、デフォルト値で自動的に初期化されます。これは、すべての基本型に対して、ゼロで埋められることを意味します。
ローカルとグローバルのどちらの場合でも、配列を宣言するとき、値を中括弧{}で囲むことにより、要素のそれぞれに初期値を割り当てることができます。例えば:
int billy [5] = { 16, 2, 77, 40, 12071 };
C標準の関連セクション(強調鉱山):
5.1.2実行環境
静的ストレージ duration 初期化する(初期値に設定)がプログラム起動前のすべてのオブジェクト。
6.2.4オブジェクトの保存期間
識別子が外部または内部リンケージで、またはストレージクラス指定子staticで宣言されているオブジェクトには、static storage durationがあります。
6.2.5タイプ
配列および構造タイプは、集合的に集合タイプと呼ばれます。
6.7.8初期化
自動ストレージ期間を持つオブジェクトが明示的に初期化されていない場合、その値は不定です。 静的ストレージ期間を持つオブジェクトが明示的に初期化されていない場合、then:
- ポインター型の場合、null pointer;に初期化されます。
- 算術型の場合、(正または符号なし)zero;に初期化されます。
- aggregateの場合、すべてのメンバーはこれらの規則に従って(再帰的に)初期化されます。
- ユニオンの場合、最初の名前付きメンバーはこれらの規則に従って(再帰的に)初期化されます。