const int i = 100;
int *j = &i;
int array[i] = {0};
これは合法ですか?&i がないと、i と 100 がシンボル テーブルに追加されることをどこかで読みましたが、&i があるため、i の格納が強制され、コンパイル時に 100 が i に格納されます。したがって、コンパイラは (ストレージから) i の値を読み取って配列を割り当てることができません。これは本当ですか?
C90およびC99では、定義int array[i] = {0};
は合法ではありません(何をするかに関係なくi
)。
ファイルスコープで宣言された配列は、長さとして整数定数式を持っている必要があります(6.5.4.2または6.7.5.2、§2、それぞれ)
定義に関数/ブロックスコープがある場合でも、それは違法です。
int *j = &i;
である必要がありますconst int *j = &i;
。その後、あなたのコードは合法です。
編集:C++で
変数がコンパイル時の定数値と物理ストレージの両方を持つことができない理由はまったくありません。したがって、それは言語の標準に依存します。
C++ では、整数定数をコンパイル時の定数にすることができます。C はありません。Cもコンパイルする一部のC++コンパイラは、両方の言語の一部の機能を組み合わせて一致させるため、コンパイラはそれを標準の拡張として受け入れる場合があります。
これは合法ですか?&i がないと、i と 100 がシンボル テーブルに追加されることをどこかで読みましたが、&i があるため、i の格納が強制され、コンパイル時に 100 が i に格納されます。したがって、コンパイラは (ストレージから) i の値を読み取って配列を割り当てることができません。これは本当ですか?
C99 標準の言語は次のとおりです。
6.7.3 型修飾子
...
3 修飾型に関連付けられたプロパティは、左辺値である式に対してのみ意味があります。114)
114) 実装は、ストレージの読み取り専用領域にconst
ないオブジェクトを配置する場合があります。volatile
さらに、実装では、そのアドレスが使用されない場合、そのようなオブジェクトにストレージを割り当てる必要はありません。
つまり、ある意味では正しいのですが、この場合はあまり関係ありません。コンパイラは、その値を他の場所で使用するためのストレージを作成する必要はありません。の代わりにi
の値を持つ即値オペランドを使用するだけです。いずれにせよ、ラインは不要です。 100
i
int j = &i;
i
整数定数式ではありません。つまり、コンパイル時の定数ではありません (C では、この点で C++ は異なります)。これは、有効期間中に値を変更できないランタイム変数です。
C99 では、実行時変数を使用して配列サイズを指定できますconst
。
const int i = 100;
int array[i];
array
の 100 要素の配列として割り当てられint
ます。ただし、VLA では初期化子を使用できないため、無効int array[i] = {0};
です。
繰り返しますが、C++ は異なり、VLA をまったくサポートしていません。しかし、i
is が宣言さconst
れているため、C++ はそれをコンパイル時の定数として扱います。つまり、コードは正当な C++ である必要があります (とにかく、私のためにビルドされます)。
C99 からの詳細:
6.7.5.2 配列宣言子
...
4 サイズが存在しない場合、配列型は不完全型です。サイズが*
式ではなく である場合、配列型はサイズが指定されていない可変長配列型であり、関数プロトタイプ スコープの宣言でのみ使用できます。124)それでも、そのような配列は完全な型です。サイズが整数定数式で、要素の型に既知の定数サイズがある場合、配列型は可変長配列型ではありません。それ以外の場合、配列タイプは可変長配列タイプです。
...
6.7.8 初期化
...
3 初期化されるエンティティの型は、サイズが不明な配列または可変長配列型ではないオブジェクト型でなければなりません。
124) したがって、* は、定義ではない関数宣言でのみ使用できます (6.7.5.3 を参照)。