Який розмір перерахунку в С?


140

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


1
Тож якщо я добре розумію, 2 ^ 32 перерахунків вам недостатньо? Або це питання про відчуження, чому вам потрібні 64, а не 32, мені дуже цікаво.
jokoon

1
@jokoon: Я, чесно кажучи, вже не пам'ятаю. Я думаю, я хотів, щоб переліки містили значення, більші за 2 ^ 32-1.
mipadi

Одне використання було б, якщо вам потрібен союз між перерахунком та покажчиком.
Демі

Відповіді:


97

enumТільки гарантовано бути досить великим , щоб тримати intцінності. Компілятор вільний вибирати використаний фактичний тип на основі визначених констант перерахування, щоб він міг вибрати менший тип, якщо він може представляти визначені вами значення. Якщо вам потрібні константи перерахування, які не вписуються у intви, для цього вам потрібно буде використовувати спеціальні розширення для компілятора.


12
Ваше перше речення, здається, суперечить вашому останньому. Чи є обмеження, що а enumмає бути більшим за intабо меншим? Після відповіді @MichaelStum вашим першим реченням має бути " enumГарантоване лише те, що вписується у intзначення".
HaskellElephant

Оскільки некрасивий хакер-чутливий хакер на платформах доповнює дві (це всі системи в наші дні?), Ви можете змусити перерахунок бути таким же великим, як int, переконавшись, що він містить негативні значення. Хоча це не рекомендується техніка.
persiflage

7
Ця відповідь, схоже, говорить про те, що перерахунок такий же великий, як і int. Відповідь Майкла Штума , в якій згадується C99, говорить про те, що перерахунок може бути таким же маленьким, як а char.
Френк Кустерс

3
Перше речення цієї відповіді неправильне. enumТільки гарантовано бути досить великим , щоб утримувати значення найбільшого переписувача в перерахуванні.
ММ

91

Взяте з чинного стандарту 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

3
Помітно: константа перерахування та тип перерахування - це не одне і те ж . Перші - це вміст списку оголошень перерахунків, останні - фактична змінна. Отже, хоча константи перерахування повинні бути int, фактична змінна перерахування може бути іншого типу. Це добре відома невідповідність стандарту.
Лундін

1
Для уточнення точки Лундін: За enum my_enum { my_value }, my_valueматиме тип int, але enum my_enumможе мати певний тип реалізації , які повинні , по крайней мере , представляти всі значення перерахування. Так my_valueможе бути звуження перетворення до enum my_enum, але це гарантовано не переповнює.
P O'Conbhui

17

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

Приклад з GCC (документація в посібнику GCC ):

enum ord {
    FIRST = 1,
    SECOND,
    THIRD
} __attribute__ ((__packed__));
STATIC_ASSERT( sizeof(enum ord) == 1 )

11
Насправді, наскільки я бачу, це не порушує стандарт. Як пояснено у відповіді Майкла Стума, стандарт дозволяє компілятору вибрати фактичний тип переліків, доки всі значення відповідають.
sleske

2
Я працював з компіляторами MacOS C ++, які експлуатують обмежений діапазон значень у enum, щоб зберігати їх у менших типах. Не можу згадати, чи це був 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};

1
Хоча цей код може відповісти на питання, надаючи додатковий контекст щодо того, як та / або чому він вирішує проблему, покращить довгострокове значення відповіді.
леопал

-1

У нас немає контролю над розміром enumзмінної. Це повністю залежить від реалізації, і компілятор дає можливість зберігати ім'я для цілого числа, використовуючи enum, таким чином enum, слідкує за розміром цілого числа.


-1

У мові С 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

11
Питання не в C ++.
Michas

4
важливі речі, які потрібно усвідомити, перш ніж писати більше C або C ++: Тільки тому, що вона компілюється, не означає, що це законно відповідно до Стандарту. Тільки тому, що ви отримуєте заданий результат, це не означає, що Стандарт говорить, що ви завжди будете, або що інші користувачі будуть, коли вони запускають ваш код. На такі запитання потрібна відповідь, що посилається на Стандарт або принаймні визначений специфікацією специфікацій для даного компілятора / ABI. Просто скласти та запустити програму та побачити один результат за один день не дає уроку з таких питань (і зовсім мало про що-небудь інше).
підкреслюй_d
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.