マクロまたは列挙型をいつ使用するかについて混乱しています。どちらも定数として使用できますが、それらの違いは何ですか?また、どちらかの利点は何ですか? それは何らかの形でコンパイラレベルに関連していますか?
7 に答える
C では、実際の列挙に列挙型を使用するのが最善です。名前を指定できる複数の値の 1 つを変数が保持できる場合です。列挙型の利点の 1 つは、列挙型の switch ステートメントでいずれかのケースが欠落していないなど、言語が必要とする以上のチェックをコンパイラが実行できることです。列挙型識別子もデバッグ情報に反映されます。デバッガーでは、識別子名を単なる数値ではなく、列挙型変数の値として表示できます。
列挙型は、整数型のシンボリック定数を作成する副作用のためにのみ使用できます。例えば:
enum { buffer_size = 4096 }; /* we don't care about the type */
この慣行はそれほど広く普及していません。1 つにはbuffer_size
、列挙型ではなく整数として使用されます。その値は列挙型として表されないため、デバッガーは にレンダリング4096
しません。一部をbuffer_size
宣言すると、 として表示されません。この状況では、列挙定数はコンパイル時に消えるため、マクロである可能性があります。また、正確なタイプを制御できないなどの欠点もあります。(翻訳の前処理段階の出力がテキストとしてキャプチャされている状況では、いくつかの小さな利点があるかもしれません。マクロは 4096 に変わりますが、そのままになります)。char array[max_buffer_size];
sizeof array
buffer_size
buffer_size
buffer_size
プリプロセッサ シンボルを使用すると、次のことが可能になります。
#define buffer_size 0L /* buffer_size is a long int */
C の<limits.h>
ようなさまざまな値UINT_MAX
はプリプロセッサ シンボルであり、enum シンボルではないことに注意してください。これには十分な理由があります。これらの識別子は正確に決定された型を持つ必要があるためです。プリプロセッサ シンボルのもう 1 つの利点は、その存在をテストしたり、その値に基づいて決定を下したりできることです。
#if ULONG_MAX > UINT_MAX
/* unsigned long is wider than unsigned int */
#endif
もちろん、列挙定数もテストできますが、結果に基づいてグローバル宣言を変更できるような方法ではできません。
列挙型もビットマスクには適していません。
enum modem_control { mc_dsr = 0x1, mc_dtr = 0x2, mc_rts = 0x4, ... }
値がビットごとの OR と組み合わされると、型の外側にある値が生成されるため、意味がありません。そのようなコードは、タイプ セーフな列挙型を持つ C++ に移植された場合にも頭痛の種になります。
マクロと列挙型の間にはいくつかの違いがあり、これらのプロパティのいずれかが特定の定数としてそれらを (不) 適切にする可能性があることに注意してください。
- 列挙型は署名されています (int と互換性があります)。符号なしの型が必要なコンテキスト (特にビット単位の操作を考えてください!) では、列挙型は使用できません。
- long long が int より広い場合、大きな定数は列挙型に収まりません。
- 列挙型のサイズは (通常)
sizeof(int)
です。小さな値の配列 (たとえばCHAR_MAX
) の場合char foo[]
、配列ではなくが必要になる場合がありますenum foo[]
。 - 列挙型は整数です。持つことはできません
enum funny_number { PI=3.14, E=2.71 }
。 - 列挙型は C89 の機能です。K&R コンパイラ (確かに古い) はそれらを理解していません。