次のコードがエラーをスローするのはなぜですか?
const int a = 5;
int b[a]={1,2,3,4,5};
また、「const」キーワードなしで上記のコードをコンパイルしようとすると、同じエラーが発生しました。
int a = 5;
int b[a]={1,2,3,4,5};
なぜそうですか?ここで行っている間違いは何ですか?
また、別の質問:コード内で定数が実際の値で置き換えられるのはいつか、つまり変数を宣言する場合は次のようになります:const int x = 5;変数xにRAMにメモリが割り当てられていないが、ROMの値が5であり、xが単にコードのxのすべての場所に値5がありますが、これはいつ発生しますか?コンパイル時間?起動時間?前処理時間?
PS:私は、デスクトップで実行されているCではなく、Embedded C(マイクロコントローラーなどで実行されている)について話しています。したがって、組み込みシステムにはROM(フラッシュ、EEPROM ...)が必要です。その場合はどうなりますか?
これは単に言語の制限です。静的にバインドされた配列のサイズは定数式である必要があり、残念ながらCではリテラル定数やsizeof
式などのようなものだけですが、notconst
- typed変数。
(サイモンが指摘したように、C99からruntime-bounded array、または「可変長配列」もあり、そのサイズは任意の変数の値で指定できます。しかし、それは別の動物です。)
static const int
が実際に定数式であり、C++ 11が新しいキーワードconstexpr
を追加して、さらに一般的なことを可能にするC++でルールが異なることを聞いてください。 「コンパイル時に合理的に決定できる」値を持つより多くのものを包含する定数式の使用。
Cでは、const
はread-onlyの誤った呼び名です。 const
変数は値を変更できます。宣言しても大丈夫です
const volatile int timer_tick_register; /* A CPU register. */
読み取りごとに異なる値を取得できますが、書き込みはできません。したがって、言語仕様はconst
修飾オブジェクトnotを配列サイズに適した定数式として扱います。
VLAの2つの主要な代替手段:enum
およびマクロ
enum
の場合:
enum N { N = 5 };
int is[N];
これは、enumメンバーが定数式であるため機能します。 enumメンバーはANSI-Cの配列のサイズにできますか?
マクロあり:
#define N 5
int is[N];
enum
sの利点は、enum
sにスコープがあり、コンパイル手順の一部であるため、エラーメッセージが改善される可能性があることです。
マクロの利点は、定数のタイプをより詳細に制御できることです(例:#define N 1
vs #define N 1u
)、enum
sはいくつかの実装定義型に固定されています: sizeof(enum sizeof(int)、always?)==しかし、これはそれほど重要ではありません場合。
VLAを避ける理由
編集:Wikipediaで、C11が可変長配列をoptional機能に委譲したことを読んでください。しかし、後半はあなたの他の質問のいくつかに答えます:)
Kerrek SBの投稿の補足として、C99(ISO/IEC 9899:1999)には可変長配列の概念があります。標準では次の例を示します。
#include <stddef.h>
size_t fsize3(int n)
{
char b[n+3]; // variable length array
return sizeof b; // execution time sizeof
}
sizeof
演算子は次のように拡張されます。
Sizeof演算子は、そのオペランドのサイズ(バイト単位)を生成します。これは、式または括弧で囲まれた型の名前です。サイズは、オペランドのタイプから決定されます。結果は整数です。 オペランドの型が可変長配列型の場合、オペランドが評価されます;それ以外の場合、オペランドは評価されず、結果は整数定数になります。
別の素敵な例は wikipedia にあります。
静的に宣言された変数を可変長配列にすることはできません。
あなたの他の質問のいくつかに関して:
Q:コード内で定数が実際の値に置き換えられるのはいつですか?
定数がconst変数の場合、「置換」されることはなく、常にメモリの領域としてアクセスできます。これは、アドレス演算子&
がまだ変数を処理する必要があるためです。ただし、変数アドレスが使用されない場合は、「置換」され、メモリが割り当てられない可能性があります。 C標準から:
実装は、ストレージの読み取り専用領域に揮発性ではないconstオブジェクトを配置できます。さらに、そのアドレスが使用されない場合、実装はそのようなオブジェクトにストレージを割り当てる必要はありません。
次の質問...
Q:変数<x>のRAMにメモリが割り当てられていないことを知っていますが、ROMの定数変数領域は値5を保持します
これはシステムによって異なります。 ROMがあり、コンパイラがROMの場所を知っている場合、それはROMに配置される可能性があります。 ROMがない場合、コンパイラ(実際にはリンカ)が持つ唯一の選択肢はRAMです。
Q:xは、コードでxが出現するすべての場所で値5に置き換えられます。しかし、これはいつ起こりますか?コンパイル時間?起動時間?前処理時間?
前述のように、これはむしろ定数の使用方法に依存します。 const変数のアドレスが使用されず、コンパイラーが十分に賢い場合、コンパイル時に。それ以外の場合、「置換」は発生せず、メモリ内の場所を含む値です。この場合、メモリ内の変数の配置はリンク時に発生します。前処理中にneverは発生しません。
言及する価値があるかもしれません、ここで使用できます
int b[] = {1, 4, 5};
要素の数が必要な場合
size_t sz = sizeof(b)/sizeof(b[0]);
定数、フラッシュ、RAMの保存場所を決定するのはツールチェーン次第だと思います