Форум » C/C++ » Баг MS VS++2010: некорректное преобразование перечислительной константы » Ответить

Баг MS VS++2010: некорректное преобразование перечислительной константы

Сыроежка: Если скомпилировать и выполнить следующую программу в среде MS VC++ 2010, при этом в свойствах проекта задать значение "Нет" для опции "Отключить расширения языка" [pre2] #include "stdafx.h" #include <climits> #include <iostream> #include <typeinfo> int _tmain(int argc, _TCHAR* argv[]) { std::cout << typeid( UINT_MAX ).name() << std::endl; enum E { e1 = UINT_MAX, e2, e3 }; std::cout << "\ne1 = " << e1 << std::endl; std::cout << "e2 = " << e2 << std::endl; std::cout << "e3 = " << e3 << std::endl; return 0; }[/pre2] то на выходе будет получен следующий результат: [quote]unsigned int e1 = -1 e2 = 0 e3 = 1[/quote] При этом компиляция пройдет без каких-либо предупреждений со стороны компилятора. Если же задать значение "Да" для опции "Отключить расширения языка" в свойствах проекта, то будет получен тот же результат выполнения программы, но при этом компилятор выдаст несколько следующих предупреждений: [quote](16): warning C4340: e2: значение из положительного стало отрицательным (16): warning C4341: e2: значение со знаком лежит вне диапазона для перечисляемых констант (16): warning C4309: инициализация: усечение константного значения (18): warning C4309: аргумент: усечение константного значения[/quote] Если же этот пример (убрав синтаксические особенности, свойственные MS VC++ 2010) скомпилировать и выполнить с помощью компилятора GCC 4.7.1, то будет получен такой результат: [quote]j e1 = 4294967295 e2 = 4294967296 e3 = 4294967297[/quote] Примечание: В этом выводе буквой j обозначен тип unsigned int. Так как это зависит от реализации, какие обозначения для типов будут выводиться функцией-членом name() Как видно, получен совершенно другой результат. То есть перечислительные константы при неявном преобразовании к целочисленному типу имеют тот тип, который в состоянии вместить значения UINT_MAX + 1 и UINT_MAX + 2, которые соответствуют перечислительным константам e2 и e3. Если обратиться к параграфу №3 раздела 4.5 Integral promotions стандарта С++, то можно в нем прочесть следующее [quote]3 A prvalue of an unscoped enumeration type whose underlying type is not fixed (7.2) can be converted to a prvalue of the first of the following types that can represent all the values of the enumeration (i.e., the values in the range bmin to bmax as described in 7.2): int, unsigned int, long int, unsigned long int, long long int, or unsigned long long int.[/quote] Кроме того в параграфе № 5 раздела 7.2 Enumeration declarations также написано, что [quote]If the underlying type is not fixed, the type of each enumerator is the type of its initializing value: — If an initializer is specified for an enumerator, the initializing value has the same type as the expression and the constant-expression shall be an integral constant expression (5.19). — If no initializer is specified for the first enumerator, the initializing value has an unspecified integral type. — Otherwise the type of the initializing value is the same as the type of the initializing value of the preceding enumerator unless the incremented value is not representable in that type, in which case the type is an unspecified integral type sufficient to contain the incremented value. If no such type exists, the program is ill-formed.[/quote] То есть это означает, что для перечислительной константы e2 компилятор должен был назначить тот тип, который вмещает значение UINT_MAX + 1. Поэтому на мой взгляд имеет место очевидный баг компилятора MS VC++ 2010. Если у кого уже установлен компилятор MS VC++ 2012, то хорошо бы было узнать, исправлен ли этот баг в новой версии компилятора.

Ответов - 1

Сыроежка: Как указал Niels Dekker в своем сообщении к отчету о дефекте, посланному мною в Майкрософт, этот баг присутствует и в релизе компилятора MS VC++ 2013. Вот пример кода, приведенный Niels Dekker, который воспроизводит данный баг в MS VC++ 2013 [pre2] #include <climits> enum { N = LLONG_MAX }; static_assert( N == LLONG_MAX, ""); [/pre2] Ознакомиться с отчетом можно по ссылке http://connect.microsoft.com/VisualStudio/feedback/details/768575/deducing-incorrect-underlying-type-for-an-unscoped-enumeration



полная версия страницы