enum
型の列挙子の数に関係なく、(それぞれ 16 ビットまたは 32 ビットのアーキテクチャで)サイズが常に 2 または 4 バイトになるのはなぜですか?
コンパイラはenum
を と同じように扱いunion
ますか?
C と C++ の両方で、型のサイズenum
は実装定義であり、整数型のサイズと同じです。
一般的なアプローチは、すべてのenum
型を と同じサイズにint
することです。これは、通常、最も効率的なアクセスを可能にする型であるためです。たとえば、これを 1 バイトにすると、ごくわずかなスペースしか節約できませんが、CPU アーキテクチャによっては、それにアクセスするために、より大きく、より遅いコードが必要になる可能性があります。
C では、列挙定数は type の定義によるものint
です。与えられた:
enum foo { zero, one, two };
enum foo obj;
式zero
は typeですint
がobj
、 typeenum foo
であり、 と同じサイズである場合とない場合がありますint
。定数が 型int
であることを考えると、列挙型を同じサイズにする方が簡単な傾向があります。
C++ では、規則が異なります。定数は列挙型です。しかし、繰り返しになりますが、効率上の理由から、各タイプを 1 つの「単語」にするのが最も理にかなっていますenum
。これは通常、 のサイズです。int
また、2011 ISO C++ 標準では、型の基になる整数型を指定する機能が追加されましたenum
。たとえば、次のように記述できます。
enum foo: unsigned char { zero, one, two };
foo
これにより、型と定数zero
、one
、および の両方two
が 1 バイトのサイズを持つことが保証されます。C にはこの機能がなく、2011 年より前の古い C++ コンパイラではサポートされていません (言語拡張機能として提供されている場合を除く)。
(余談が続きます。)
では、大きすぎて に収まらない列挙定数がある場合はどうなるint
でしょうか。これを行うには、 2 31、さらには 2 15の個別の定数は必要ありません。
#include <limits.h>
enum huge { big = INT_MAX, bigger };
の値はbig
でINT_MAX
、通常は 2 31 -1 ですが、2 15 -1 (32767)まで小さくすることができます。の値bigger
は暗黙的にbig + 1
です。
C++ では、これで問題ありません。コンパイラはhuge
、値を保持するのに十分な大きさの基になる型を選択するだけですINT_MAX + 1
。(そのような型があると仮定します;int
が 64 ビットで、それより大きな整数型がない場合、それは不可能です。)
Cでは列挙定数は 型int
なので、上記は無効です。N1570 6.7.2.2p2に記載されている制約に違反しています。
列挙定数の値を定義する式は、 intとして表現可能な値を持つ整数定数式でなければなりません 。
したがって、コンパイラはそれを拒否するか、少なくとも警告する必要があります。たとえば、gcc は次のように述べています。
エラー: 列挙値のオーバーフロー
列挙型は構造体ではなく、一連の整数に名前を付ける方法にすぎません。この型の変数のサイズは、基になる整数型のサイズと同じです。これは、列挙型で最大値を保持するために必要な型になります。したがって、すべての型が同じ整数型に収まる限り、サイズは変わりません。
OPは、列挙型が宣言された値を格納するある種のコレクションであると想定しているように思えます。これは正しくありません。
C/C++ の列挙は、値の範囲が厳密に定義された単純な数値変数です。列挙型の名前は、数値のエイリアスのようなものです。
ストレージ サイズは、列挙値の量の影響を受けません。ストレージ サイズは実装で定義されますが、ほとんどはsizeof(int)
.
のサイズは、enum
「少なくとも宣言で指定された値のいずれかを含むのに十分な大きさの整数型」です。多くのコンパイラはint
(おそらくunsigned
) のみを使用しますが、最適化やその他の要因に応じてchar
またはを使用するコンパイラもあります。short
可能なenum
値が 128 個未満の は a char
( の場合は 256 unsigned char
) に収まり、 a をオーバーフローするには 32768 (または 65536) の値が必要であり、ほとんどの最新のシステムでshort
は を超えるには 20 億または 40 億の値が必要です。int
Anenum
は本質的に、一連の異なる定数を定義するためのより良い方法です。これの代わりに:
#define FIRST 0
#define SECOND 1
...
あなただけ:
enum myenum
{ FIRST,
SECOND,
...
};
誤って重複した値を割り当てるのを避けるのに役立ち、特定の値が何であるかを気にする必要さえなくなります (本当に必要な場合を除きます)。
小さい型がすべての値に適合する場合enum
よりも型を小さくすることの大きな問題は、列挙定数の数に依存する翻訳単位の ABI を作成することです。int
たとえば、enum
パブリック インターフェイスの一部として 256 個の定数を持つ型を使用するライブラリがあり、コンパイラがその型を 1 バイトとして表すことを選択したとします。ここで、ライブラリに新しい機能を追加し、257 個の定数が必要になったとします。コンパイラは新しいサイズ/表現に切り替える必要があり、古いインターフェイス用にコンパイルされたすべてのオブジェクト ファイルは、更新されたライブラリと互換性がなくなります。再び機能させるには、すべてを再コンパイルする必要があります。
したがって、正常な実装では常にint
forenum
型が使用されます。