Каков размер данных типа enum в C ++? - PullRequest
57 голосов
/ 14 ноября 2011

Это тестовый вопрос по С ++, а не домашняя работа.

#include <iostream>
using namespace std;
enum months_t { january, february, march, april, may, june, july, august, september,    
  october, november, december} y2k;

 int main ()
  {
    cout << "sizeof months_t is  " << sizeof(months_t) << endl;
    cout << "sizeof y2k is  " << sizeof(y2k) << endl;
    enum months_t1 { january, february, march, april, may, june, july, august,    
       september, october, november, december} y2k1;
    cout << "sizeof months_t1 is  " << sizeof(months_t1) << endl;
    cout << "sizeof y2k1 is  " << sizeof(y2k1) << endl;
 }

Выход:

Размер месяца_ 4
Размер Y2K составляет 4
размер month_t1 составляет 4
размер y2k1 составляет 4

Почему размер всех этих 4 байтов? Не 12 х 4 = 48 байт?
Я знаю, что элементы объединения занимают одно и то же место в памяти, но это перечисление.

Ответы [ 8 ]

100 голосов
/ 14 ноября 2011

Это контрольный вопрос по С ++, а не домашняя работа.

Тогда ваш интервьюер должен освежить свои воспоминания о том, как работает стандарт C ++. И я цитирую :

Для перечисления, базовый тип которого не фиксирован, базовый тип является целочисленным типом, который может представлять все значения перечислителя, определенные в перечислении.

Вся часть, базовый тип которой не является фиксированным, взята из C ++ 11, но все остальные - стандартные C ++ 98/03. Короче говоря, sizeof(months_t) это , а не 4. Это тоже не 2. Это может быть любым из них. Стандарт не говорит, какого размера он должен быть; только то, что он должен быть достаточно большим, чтобы соответствовать любому перечислителю.

почему весь размер составляет 4 байта? не 12 х 4 = 48 байт?

Потому что перечисления не являются переменными. Члены перечисления не являются фактическими переменными; это просто полу-безопасная форма #define. Это способ хранения числа в удобном для читателя формате. Компилятор преобразует все виды использования перечислителя в фактическое числовое значение.

Перечислители - это просто еще один способ говорить о числе. january это просто сокращение для 0. А сколько места занимает 0? Это зависит от того, где вы храните его.

47 голосов
/ 14 ноября 2011

Размер составляет четыре байта, потому что enum хранится как int.Имея только 12 значений, вам действительно нужно только 4 бита, но 32-битные машины обрабатывают 32-битные величины более эффективно, чем меньшие.

0 0 0 0  January
0 0 0 1  February
0 0 1 0  March
0 0 1 1  April
0 1 0 0  May
0 1 0 1  June
0 1 1 0  July
0 1 1 1  August
1 0 0 0  September
1 0 0 1  October
1 0 1 0  November
1 0 1 1  December
1 1 0 0  ** unused **
1 1 0 1  ** unused **
1 1 1 0  ** unused **
1 1 1 1  ** unused **

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

9 голосов
/ 14 ноября 2011

Это зависит.Стандарт требует только того, чтобы он был достаточно большим, чтобы содержать все значения, поэтому формально перечисление типа enum foo { zero, one, two }; должно иметь размер только один байт.Однако в большинстве реализаций эти перечисления достигают целых чисел (это быстрее на современном оборудовании; более того, это необходимо для совместимости с C, где перечисления в основном прославляют целые числа).Однако обратите внимание, что C ++ допускает перечисления с инициализаторами вне диапазона int, и для этих перечислений размер, конечно, также будет больше.Например, если у вас есть enum bar { a, b = 1LL << 35 };, тогда ваше перечисление будет больше 32 бит (скорее всего, 64 бит) даже в системе с 32-битными целыми числами (обратите внимание, что в C это перечисление не будет разрешено).

6 голосов
/ 14 ноября 2011

Перечисление типа typedef для типа int (вида).

Таким образом, тип, который вы определили, имеет 12 возможных значений, однако одна переменная имеет только одно из этих значений.

Думайте об этом так, когда вы определяете перечисление, вы в основном определяете другой способ присвоения значения типа int.

В приведенном вами примере январь - это еще один способ сказать 0, feb - это другой способ сказать 1 и т. Д., Пока декабрь не станет другим способом сказать 11.

4 голосов
/ 25 апреля 2012

С моими устаревшими перечислениями компилятора Borland C ++ Builder могут быть 1,2 или 4 байта, хотя у него есть флаг, который можно перевернуть, чтобы заставить его использовать целые числа.

Я думаю, это зависит от компилятора.

4 голосов
/ 14 ноября 2011

Поскольку это размер экземпляра типа - предположительно, значения enum хранятся здесь как (32-битные / 4-байтовые) целые числа.

3 голосов
/ 22 марта 2017

Мне нравится объяснение от EdX (Microsoft: DEV210x Введение в C ++) для аналогичной проблемы:

"Перечисление представляет буквенные значения дней в виде целых чисел. Обращаясь к таблице числовых типов, вы видите, что int занимает 4 байта памяти. Для 7 дней x 4 байта каждому потребуется 28 байтов памяти, если бы все перечисление было хранится, но компилятор использует только один элемент перечисления, поэтому размер в памяти фактически равен 4 байта. "

1 голос
/ 14 ноября 2011

Перечисление - это почти целое число. Чтобы упростить много

enum yourenum { a, b, c };

почти как

#define a 0
#define b 1
#define c 2

Конечно, это не совсем так. Я пытаюсь объяснить, что enum - это какая-то кодировка ...

...