Подтвердить что ты не робот

Должен ли код не печатать "1 1" вместо "4 4"?

В соответствии с §7.2/5 и §7.2/6 не следует использовать ниже 1 1 вместо 4 4?

#include <iostream>
enum A { a = (char)1, b, c };   //  underlying type is not fixed

int main() {
    std::cout << sizeof(a) << ' ' << sizeof(A) << '\n';
}

Edit

Из §7.2/5:

Если базовый тип не является фиксированным, тип каждого перечислителя тип его инициализирующего значения:

- Если для счетчика указан инициализатор, инициализация значение имеет тот же тип, что и выражение и константное выражение должно быть интегральным постоянным выражением (5.19).

4b9b3361

Ответ 1

Если вы явно не определяете базовый тип, тогда компилятор может выбрать тип интеграла, который соответствует значениям. Чтобы установить базовый тип в С++ 11, вы можете использовать это:

enum A : char { a = 1, b, c }; 
       ^^^^^^

Ваш способ не заставит компилятор использовать char вместо int.

Ответ 2

Это определенная реализация: тот факт, что все значения enum вписываются, скажем, в uint8_t, не заставляют компилятор выбирать однобайтовое представление для перечисления.

Основной тип перечисления является интегральным типом, который может представлять все значения перечисления, определенные в перечислении. Определяется реализацией, какой интегральный тип используется в качестве базового типа для перечисления, за исключением того, что базовый тип не должен быть больше, чем int, если значение перечислителя не может быть помещено в int или unsigned int, (выделено мной)

В вашем случае кажется, что разработчики компилятора выбирают int, который занимает четыре байта на вашей платформе - совершенно правильный выбор.

Ответ 3

В предложении, указанном в 7.2/5, описаны типы счетчиков. Но счетчики являются лишь частью определения перечисления. Основной тип перечисления достаточно велик, чтобы удерживать значения всех счетчиков, в соответствии с 7.2/6:

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

Таким образом, гарантируется, что ваш базовый тип не больше int (так как int может представлять 0, 1 и 2). Верно, что тип вашего первого счетчика char внутри определения перечисления, но все фактические значения перечисления имеют тип A. Чтобы фактически управлять базовым типом, используйте синтаксис enum-base (например, enum A : char), и для его запроса вы можете использовать признак std::underlying_type.

Если вы действительно хотите увидеть влияние типа перечисления в определении, вы можете попробовать что-то вроде этого:

enum Foo { a = '\010', b = sizeof(a) };

std::cout << typeid(b).name() << "\n";    // some variant of "Foo"
std::cout << b << "\n";                   // "1"
std::cout << sizeof(b) << "\n";           // implementation-defined, not greater
                                          // than sizeof(int)

Ответ 4

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

Прежде чем говорить, что это безумие, и он должен использовать самый маленький тип, который работает (что, кстати, GCC будет делать, если вы используете __attribute__((packed))), подумайте о совместимости с ABI. Если вы отпустите библиотеку, которая использует тип перечисления, вы предпочтете, чтобы размер этого типа не изменился. Если все перечисления начинаются с 4 байтов, вероятность увеличивается, что будет просто переходить на обновленную библиотеку.