Каков размер перечисления в C?

142

Я создаю набор значений перечисления, но мне нужно, чтобы каждое значение перечисления было шириной 64 бита. Если я правильно помню, enum обычно имеет тот же размер, что и int; но я думал, что где-то читал, что (по крайней мере, в GCC) компилятор может сделать перечисление любой ширины, необходимой для хранения их значений. Итак, возможно ли иметь перечисление шириной 64 бита?

мипади
источник
1
Так что, если я хорошо понимаю, вам мало 2 ^ 32 перечислений? Или это проблема выравнивания, зачем вам 64, а не 32, мне очень любопытно.
jokoon
1
@jokoon: Честно говоря, я больше не помню. Я думаю, что хотел, чтобы перечисления содержали значения больше 2 ^ 32-1.
mipadi 04
Один из вариантов использования - если вам нужно объединение перечисления и указателя.
Деми

Ответы:

99

enumГарантируется, что An будет достаточно большим для хранения intзначений. Компилятор может выбрать фактический используемый тип на основе определенных констант перечисления, поэтому он может выбрать меньший тип, если он может представлять определяемые вами значения. Если вам нужны константы перечисления, которые не подходят, intвам нужно будет использовать для этого расширения, специфичные для компилятора.

Роберт Гэмбл
источник
12
Кажется, ваше первое предложение противоречит последнему. Ограничение enumдолжно быть больше intили меньше? После ответа @MichaelStum ваше первое предложение должно быть « enumГарантированно соответствует только intзначению».
HaskellElephant
В качестве уродливого взлома, чувствительного к реализации на платформах с двойным дополнением (это все системы в наши дни?), Вы можете заставить перечисление быть таким большим, как int, убедившись, что оно содержит отрицательные значения. Однако это не рекомендуемый метод.
persiflage
7
Этот ответ, по-видимому, предполагает, что перечисление имеет размер int. Ответ Майкла Стама , который ссылается на C99, говорит, что перечисление может быть размером с char.
Фрэнк
3
Первое предложение этого ответа неверно. enumТолько гарантированно быть достаточно большим , чтобы удерживать значение наибольшего переписчика в перечислении.
MM
95

Взято из текущего стандарта C (C99): http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

6.7.2.2 Спецификаторы перечисления
[...]
Ограничения
Выражение, определяющее значение константы перечисления, должно быть целочисленным константным выражением, значение которого может быть представлено как int.
[...]
Каждый перечислимый тип должен быть совместим с char, целочисленным типом со знаком или целым числом без знака. Выбор типа определяется реализацией, но должен обеспечивать представление значений всех элементов перечисления.

Не то, чтобы компиляторы хорошо следовали стандарту, но по сути: если ваше перечисление содержит что-то еще, кроме int, вы находитесь в глубоком «неподдерживаемом поведении», которое может снова укусить вас через год или два.

Майкл Штум
источник
3
имея только это, я думаю, верно следующее: enum {LAST = INT_MAX, LAST1, LAST2}; поэтому LAST2 не может быть представлен в int, но не было выражения, определяющего его.
Йоханнес Шауб - лит,
4
В самом PDF он определяет следующее: «Идентификаторы в списке перечислителя объявляются как константы, имеющие тип int [...]». Я пропустил это, чтобы не было слишком многословным.
Майкл Штум
2
Примечание « знаковый целочисленный тип, или целое число без знака типа». Не обязательно . и также являются целочисленными типами, и независимо от выбора реализации все значения должны соответствовать (« должны быть способны представлять значения всех членов перечисления»). intshortlong
5
Примечательно: константа перечисления и перечисляемый тип - это не одно и то же . Первые являются содержимым списка объявлений enum, вторые - фактической переменной. Таким образом, хотя константы перечисления должны быть int, фактическая переменная перечисления может быть другого типа. Это известное несоответствие в стандарте.
Lundin
3
Для уточнения точки Лундин: За enum my_enum { my_value }, my_valueбудет иметь тип int, но enum my_enumможет иметь определенный тип реализации , которые должны , по крайней мере , представлять все значения перечисления. Так my_valueможет быть сужающееся преобразование в enum my_enum, но гарантированно не переполнение.
P O'Conbhui
18

Хотя предыдущие ответы верны, у некоторых компиляторов есть варианты, позволяющие нарушить стандарт и использовать наименьший тип, который будет содержать все значения.

Пример с GCC (документация в GCC Manual ):

enum ord {
    FIRST = 1,
    SECOND,
    THIRD
} __attribute__ ((__packed__));
STATIC_ASSERT( sizeof(enum ord) == 1 )
Кевин Кокс
источник
11
На самом деле, насколько я понимаю, это не противоречит стандарту. Как объясняется в ответе Майкла Стума, стандарт позволяет компилятору выбирать фактический тип перечислений, если все значения подходят.
sleske
2
Я работал с компиляторами MacOS C ++, которые действительно используют ограниченный диапазон значений в перечислении для хранения их в меньших типах. Не могу вспомнить, был ли это Metrowerks Codewarrior или XCode. Это в рамках стандарта C ++. Вы не можете предполагать sizeof (MyEnum) == sizeof (int) в целом.
persiflage
0

Просто установите последнее значение перечисления на значение, достаточно большое, чтобы сделать его размер, который вы хотите, чтобы перечисление было, тогда оно должно быть такого же размера:

enum value{a=0,b,c,d,e,f,g,h,i,j,l,m,n,last=0xFFFFFFFFFFFFFFFF};
Scirdan
источник
2
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, как и / или почему он решает проблему, улучшит долгосрочную ценность ответа.
leopal
-1

У нас нет контроля над размером enumпеременной. Это полностью зависит от реализации, и компилятор дает возможность сохранить имя для целого числа с помощью enum, поэтому enumследует размер целого числа.

Мехул Патель
источник
-1

На языке C enumгарантированно будет иметь размер int. Существует опция времени компиляции ( -fshort-enums), чтобы сделать его как можно более коротким (это в основном полезно в случае, если значения не превышают 64 КБ). Во время компиляции нет возможности увеличить его размер до 64 бит.

рашок
источник
-6

Рассмотрим этот код:

enum value{a,b,c,d,e,f,g,h,i,j,l,m,n};
value s;
cout << sizeof(s) << endl;

На выходе будет 4. Таким образом, независимо от количества элементов, которые он enumсодержит, его размер всегда фиксирован.

тушань
источник
6
Ответ Майкла Стума правильный. Это зависит от компилятора. Вы можете попробовать это сами с IAR EWARM. IAR EWARM показывает 1 для вашего примера. Если есть до 255 элементов, он все еще показывает 1. После добавления 256-го элемента он увеличивается до 2.
desowin
12
Вопрос не в C ++.
Michas
4
важные вещи, которые необходимо понять, прежде чем писать больше на C или C ++: просто потому, что он компилируется, не означает, что он законен в соответствии со стандартом. Тот факт, что вы получаете заданный результат, не означает, что в стандарте говорится, что вы всегда будете получать или что другие пользователи будут выполнять ваш код. На подобные вопросы нужен ответ, который ссылается на стандарт или, по крайней мере, определенную спецификацию реализации для данного компилятора / ABI. Простая компиляция и запуск программы и просмотр одного результата за один день не дает никаких уроков по таким вопросам (и очень мало по чему-либо еще).
underscore_d