Перечисления, превышающие размер типа наибольшее число
Я хочу полностью понять, как компилятор C++ работает с enum, превышающим максимально возможное число, то есть содержащим -1
и UINT64_MAX
одновременно, т.е.
enum A {
X = -1,
Y = UINT64_MAX
};
Сначала я подумал, что компилятор не примет этот код. На самом деле он не компилируется, когда enum
заменяется enum class
, но приведенный выше пример компилируется. Согласно стандарту мы имеем для базового типа:
Объявляет тип перечисления с незаданной областью, базовый тип которого не является фиксированным (в этом случае базовый тип является целочисленным типом, определяемым реализацией, который может представлять все значения перечислителя; этот тип не больше int, если значение перечислителя не может поместиться в int или unsigned int. Если список-перечислитель пуст, базовый тип такой, как если бы перечисление имело единственный перечислитель со значением 0). (https://en.cppreference.com/w/cpp/language/enum)
Но что это значит для моего примера?
Я написал небольшую примерную программу, чтобы узнать, что происходит:
#include <iostream>
#include <cstdint>
enum A {
X = -1,
XX = -1,
Y = UINT64_MAX
};
int main()
{
std::cout << "X unsigned: " << (uint64_t)(X) << ", signed: " << (int64_t)(X) << std::endl;
std::cout << "Y unsigned: " << (uint64_t)(Y) << ", signed: " << (int64_t)(Y) << std::endl;
std::cout << "(X == XX) == " << (X == XX) << std::endl;
std::cout << "(X == Y) == " << (X == Y) << std::endl;
}
Выход:
X unsigned: 18446744073709551615, signed: -1
Y unsigned: 18446744073709551615, signed: -1
(X == XX) == 1
(X == Y) == 0
Теперь я в замешательстве. Очевидно, X и Y представляют одно и то же число, но они все еще различимы, т.е. Сравнение X == Y
неверно (но X=XX
на самом деле верно). Что здесь происходит?
Я знаю, что лучше использовать не старый enum
, а новый enum class
. Но все-таки enum
широко используется, и я хочу понять, что здесь происходит.
Ответы
Ответ 1
Ваш компилятор, скорее всего, использует 128-битный целочисленный тип со знаком в качестве базового типа в соответствии со стандартом C++.
Убедитесь сами
std::cout << sizeof(std::underlying_type<A>::type);
Ссылка: https://ideone.com/z4K0rz, выходы 16.
Вывод, который вы наблюдаете, согласуется с сужающим преобразованием этого в 64-битный тип без знака.
Ответ 2
То, что вы видите, является эффектом приведения типов, а не enum
. Ваш вывод зависит от того, как вы разыгрываете значение.
Попробуйте это: он имеет тот же результат, что и ваш, без enum
.
#include <iostream>
#include <cstdint>
int main()
{
std::cout << "X unsigned: " << (uint64_t)(-1) << ", signed: " << (int64_t)(-1) << std::endl;
return 0;
}
И вывод:
X unsigned: 18446744073709551615, signed: -1