Страницы

Поиск по вопросам

суббота, 21 декабря 2019 г.

Инициализация объекта перечислимого типа

#cpp #c #qt #qt5


В коде на С++ натолкнулся на такую инициализацию:

Specification = (BulkCode)-1;


где

BulkCode Specification;

enum BulkCode {
SETFILTER,
SETTRIGGERANDSAMPLERATE,
FORCETRIGGER}


Насколько правомерно так писать?
    


Ответы

Ответ 1



В С - разрешено. Переменные типа enum BulkCode имеют то же внутреннее представление, что и один из встроенных целочисленных типов, в который влезают все значения перечисленных констант (на выбор компилятора, char или signed/unsigned char/short/int/long/long long). Тип enum BulkCode считается integer type и приведение к нему работает по тем же правилам, что и ко встроенным целочисленным типам. Так что, независимо от того, какое представление выбрал компилятор, (enum BulkCode)-1 будет работать. Пруф раз. Пруф два. Пруф три. В С++ - нельзя, неопределенное поведение. (Конкретно для этого enum'а.) До С++17 результат был unspecified. Если была бы хотя бы одна отрицательная константа, либо если underlying type был бы указан явно как знаковый целый, то было бы разрешено. В отдельных других случаях, в зависимости от конкретных значений констант в enum'е, это может оказаться разрешено, но полагаться на это не следует, потому что правила слишком запутанные. (Читай ниже.) В С++, если у enum'а underlying type не указан явно1, то компилятор опять же выбирает его на свое усмотрение2. Однако, допустимые значения enum'а не обязательно совпадают с допустимыми значениеми его underlying type. Диапазон допустимых значений enum'а определяется так: Если в enum'е нет отрицательных констант, то диапазон - от 0 до 2^n - 1 (с наименьшим возможным положительным n, при котором все константы влезают в диапазон). Если отрицательные константы есть, то диапазон - от -2^(n-1) до 2^(n-1) - 1 (опять же, с наименьшим возможным n, при котором все константы влезают в диапазон). (На системах с one's complement и sign-magnitude представлениями целых нижняя граница для второго случая на 1 выше, но в реальности таких систем по сути нет.) В enum BulkCode {SETFILTER, SETTRIGGERANDSAMPLERATE, FORCETRIGGER}; нет отрицательных констант, так что его диапазон - от 0 до 3 (n=2, без знака). А underlying type - любой целый тип не больше int. Когда к enum'у приводится целое число, оно сначала приводится к его underlying type. Если получившийся результат не влезает в допустимый диапазон, то получаем неопределенное поведение. (До С++17 результат был unspecified.) Для того enum'а, что в вопросе, нет такого underlying type, преобразование -1 к которому дало бы 3, так что гарантированно получаем неопределенное поведение. Будь у нас хотя бы одна отрицательная константа, то -1 влезал бы в допустимый диапазон, и проблем бы не было. Однако, даже без отрицательных констант, если бы у констант были такие значения, что допустимый диапазон совпадал бы с диапазоном значений underlying type (например, хотя бы одна константа со значением больше INT_MAX, но не больше UINT_MAX), то преобразование -1 к underlying type гарантированно давало бы верхнюю границу допустимого диапазона, и неопределенного поведения бы не было. Условия очень специфичные, поэтому на это лучше не рассчитывать. Пруф раз. Пруф два. 1 - Пример явного указания: enum E : int {a,b};. 2 - Типы больше int ему разрешено брать только если константы не влезают ни в int, ни в unsigned int.

Комментариев нет:

Отправить комментарий