Jaki jest rozmiar wyliczenia w C?

140

Tworzę zestaw wartości wyliczenia, ale potrzebuję, aby każda wartość wyliczenia miała szerokość 64 bitów. Jeśli dobrze pamiętam, wyliczenie ma zazwyczaj taki sam rozmiar jak int; ale pomyślałem, że gdzieś przeczytałem, że (przynajmniej w GCC) kompilator może nadać wyliczeniu dowolną szerokość, jakiej potrzebują, aby zachować swoje wartości. Czy jest więc możliwe wyliczenie o szerokości 64 bitów?

mipadi
źródło
1
Więc jeśli dobrze rozumiem, 2 ^ 32 wyliczenia to dla ciebie za mało? A może jest to kwestia wyrównania, dlaczego potrzebujesz tych 64 zamiast 32, jestem bardzo ciekawy.
żart
1
@jokoon: Szczerze mówiąc, już nie pamiętam. Myślę, że chciałem, aby wyliczenia zawierały wartości większe niż 2 ^ 32-1.
mipadi
Jednym z zastosowań byłoby, gdybyś potrzebował unii między wyliczeniem a wskaźnikiem.
Demi,

Odpowiedzi:

97

enumJest gwarantowana tylko być na tyle duża, aby hold intwartości. Kompilator może wybrać rzeczywisty typ używany na podstawie zdefiniowanych stałych wyliczania, dzięki czemu może wybrać mniejszy typ, jeśli może reprezentować zdefiniowane wartości. Jeśli potrzebujesz stałych wyliczania, które nie pasują do elementu int, będziesz musiał użyć do tego rozszerzeń specyficznych dla kompilatora.

Robert Gamble
źródło
12
Twoje pierwsze zdanie wydaje się kolidować z ostatnim. Czy ograniczenie, że a enumpowinno być większe niż intczy mniejsze? Po odpowiedzi @MichaelStum Twoje pierwsze zdanie powinno brzmieć „ enumGwarantowane jest tylko dopasowanie do intwartości”.
HaskellElephant
Jako brzydki hack wrażliwy na implementację na platformach uzupełniających do dwóch (czy to wszystkie systemy w dzisiejszych czasach?), Możesz wymusić, aby wyliczenie było tak duże, jak int, upewniając się, że zawiera wartości ujemne. Nie jest to jednak zalecana technika.
persyflaż
7
Ta odpowiedź wydaje się sugerować, że wyliczenie jest tak duże jak int. Odpowiedź Michaela Stuma , która odwołuje się do C99, mówi, że wyliczenie może być tak małe jak char.
Frank Kusters
3
Pierwsze zdanie tej odpowiedzi jest nieprawidłowe. enumJest gwarantowana tylko być na tyle duże, aby utrzymać wartość największego wyliczający w enum.
MM
91

Zaczerpnięte z aktualnego standardu C (C99): http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

6.7.2.2 Specyfikatory wyliczenia
[...]
Ograniczenia
Wyrażenie, które definiuje wartość stałej wyliczenia, powinno być wyrażeniem stałym będącym liczbą całkowitą, którego wartość można przedstawić jako int.
[...]
Każdy wyliczony typ powinien być zgodny z typem char, typem liczby całkowitej ze znakiem lub typem liczby całkowitej bez znaku. Wybór typu jest określony przez implementację, ale powinien być zdolny do reprezentowania wartości wszystkich członków wyliczenia.

Nie żeby kompilatory były dobre w podążaniu za standardem, ale zasadniczo: jeśli twoje wyliczenie zawiera coś innego niż int, jesteś w głębokim „nieobsługiwanym zachowaniu, które może powrócić i gryźć cię za rok lub dwa”.

Michael Stum
źródło
3
mając tylko to, myślę, że ważne jest: wyliczenie {LAST = INT_MAX, LAST1, LAST2}; więc LAST2 nie jest reprezentowalne w int, ale nie było wyrażenia definiującego to.
Johannes Schaub - litb
4
W aktualnym pliku PDF określa, że: „Identyfikatory na liście modułów wyliczających są deklarowane jako stałe, które mają typ int [...]”. Pominąłem to, aby nie było zbyt szczegółowe.
Michael Stum
2
Uwaga „ podpisał typu Integer lub unsigned typu Liczba całkowita”. Niekoniecznie . i są również typami całkowitymi i niezależnie od wybranej implementacji, wszystkie wartości muszą pasować („ powinny być zdolne do reprezentowania wartości wszystkich członków wyliczenia”). intshortlong
3
Warto zauważyć: stała wyliczeniowa i typ wyliczeniowy to nie to samo . Pierwsza z nich to zawartość listy deklaracji wyliczenia, druga to rzeczywista zmienna. Więc chociaż stałe wyliczenia muszą być int, rzeczywista zmienna wyliczenia może być innego typu. Jest to dobrze znana niespójność w standardzie.
Lundin
1
Aby wyjaśnić punkt widzenia Lundina: For enum my_enum { my_value }, my_valuebędzie miał typ int, ale enum my_enummoże mieć typ zdefiniowany w implementacji, który musi przynajmniej reprezentować wszystkie wartości wyliczenia. Więc my_valuemoże mieć zawężoną konwersję do enum my_enum, ale gwarantuje, że nie przepełni.
P O'Conbhui
17

Chociaż poprzednie odpowiedzi są poprawne, niektóre kompilatory mają opcje przełamania standardu i użycia najmniejszego typu, który będzie zawierał wszystkie wartości.

Przykład z GCC (dokumentacja w podręczniku GCC ):

enum ord {
    FIRST = 1,
    SECOND,
    THIRD
} __attribute__ ((__packed__));
STATIC_ASSERT( sizeof(enum ord) == 1 )
Kevin Cox
źródło
11
Właściwie, o ile widzę, nie łamie to standardu. Jak wyjaśniono w odpowiedzi Michaela Stuma, standard pozwala kompilatorowi wybrać rzeczywisty typ wyliczeń, o ile pasują wszystkie wartości.
sleske,
2
Pracowałem z kompilatorami MacOS C ++, które wykorzystują ograniczony zakres wartości w wyliczeniu do przechowywania ich w mniejszych typach. Nie pamiętam, czy był to Metrowerks Codewarrior czy XCode. Jest to zgodne ze standardem C ++. Ogólnie nie można założyć, że sizeof (MyEnum) == sizeof (int).
persiflage
0

Po prostu ustaw ostatnią wartość wyliczenia na wartość dostatecznie dużą, aby uzyskać rozmiar, jaki ma mieć wyliczenie, powinien wtedy mieć ten rozmiar:

enum value{a=0,b,c,d,e,f,g,h,i,j,l,m,n,last=0xFFFFFFFFFFFFFFFF};
scirdan
źródło
1
Chociaż ten kod może odpowiedzieć na pytanie, dostarczenie dodatkowego kontekstu dotyczącego tego, jak i / lub dlaczego rozwiązuje problem, poprawiłoby długoterminową wartość odpowiedzi.
leopal
-1

Nie mamy kontroli nad wielkością enumzmiennej. Zależy to całkowicie od implementacji, a kompilator daje możliwość przechowywania nazwy dla liczby całkowitej przy użyciu enum, więc enumśledzi rozmiar liczby całkowitej.

Mehul patel
źródło
-1

W języku C enumgwarantowany jest rozmiar an int. Istnieje opcja czasu kompilacji ( -fshort-enums), aby uczynić go tak krótkim (jest to przydatne głównie w przypadku, gdy wartości nie są większe niż 64K). Nie ma opcji czasu kompilacji, aby zwiększyć jego rozmiar do 64 bitów.

rashok
źródło
-6

Rozważ ten kod:

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

Daje 4 jako wyjście. Więc bez względu na liczbę elementów, które enumzawiera, jego rozmiar jest zawsze stały.

tuszan
źródło
6
Odpowiedź Michaela Stuma jest prawidłowa. Jest to specyficzne dla kompilatora. Możesz to wypróbować sam z IAR EWARM. IAR EWARM pokazuje 1 dla twojego przykładu. Jeśli jest do 255 pozycji, nadal pokazuje 1. Po dodaniu 256 pozycji rośnie do 2.
desowin
11
Pytanie nie dotyczy C ++.
Michas
4
ważne rzeczy, które należy sobie uświadomić przed dalszym pisaniem C lub C ++: Tylko dlatego, że kompiluje się, nie oznacza, że ​​jest to zgodne ze standardem. Tylko dlatego, że otrzymujesz dany wynik, nie oznacza, że ​​Standard mówi, że zawsze tak będzie lub że inni użytkownicy będą to robić, gdy uruchomią Twój kod. Pytania takie jak ta wymagają odpowiedzi odwołującej się do normy lub przynajmniej specyfikacji zdefiniowanej w implementacji dla danego kompilatora / ABI. Samo skompilowanie i uruchomienie programu oraz zobaczenie jednego wyniku jednego dnia nie daje żadnej lekcji na temat takich pytań (i bardzo niewiele na temat czegokolwiek innego).
underscore_d