C ++ 11 Сужение переменной без предупреждения компилятора GCC - PullRequest
4 голосов
/ 24 ноября 2011

Концепция сужения кажется довольно простой. Однако, может кто-нибудь объяснить, почему некоторые из приведенного ниже кода вызывают «сужение» ошибок компилятора, а другие нет?

Этот код выдает ошибки там, где ожидается:

constexpr int a = 255;
unsigned char b = a;      // OK
unsigned char c = a + 1;  // Error... expected

Этот код не выдает ошибок, но может быть в порядке:

int d = 256;
unsigned char e = d;  // Maybe OK because 'd' is not constexpr

Этот код должен генерировать ошибки (если я что-то упустил):

int f = 42.0;  // Maybe OK because no fractional part
int g = 42.1;  // OK... should fail!!
constexpr float h = 42.7;
int i = h;     // OK... should fail???

Я использую g ++ 4.6.2. Я искал в базе данных ошибок GCC и не нашел ничего связанного. Спасибо!

Ответы [ 3 ]

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

Если честно, с вашими образцами я вижу немного неправильного.

Тем не менее, существует ряд случаев, когда компилятор, похоже, допускает «нарушения» стандартных правил преобразования ...:

Списки инициализаторов (§ 8.5.4)

Однако я заметил это в стандарте:

Для списков инициализаторов следующее не разрешено (§ 8.5.4, в 3. )

int ai[] = { 1, 2.0 }; // error narrowing

Под 6. далее приводится общий список примеров:

[Примечание: как указано выше, такие преобразования не допускаются на верхнем уровне при инициализации списка. — конец примечание]

int x = 999; // x is not a constant expression
const int y = 999;
const int z = 99;
char c1 = x; // OK, though it might narrow (in this case, it does narrow)
char c2{x}; // error: might narrow
char c3{y}; // error: narrows (assuming char is 8 bits)
char c4{z}; // OK: no narrowing needed
unsigned char uc1 = {5}; // OK: no narrowing needed
unsigned char uc2 = {-1}; // error: narrows
unsigned int ui1 = {-1}; // error: narrows
signed int si1 =
{ (unsigned int)-1 }; // error: narrows
int ii = {2.0}; // error: narrows
float f1 { x }; // error: might narrow
float f2 { 7 }; // OK: 7 can be exactly represented as a float
int f(int);
int a[] = { 2, f(2), f(2.0) }; // OK: the double-to-int conversion is not at the top level

Интересно, что g ++ 4.6.1 с --std=c++0x -Wall -pedantic ловит только одно из этих нарушений:

    char c3{y}; // warning: overflow in implicit constant conversion [-Woverflow]

Внешние списки инициализаторов ...

Я не думаю, что усечение числа с плавающей точкой до int считается narrowing.

Это просто четкое преобразование, очень похожее на

int i = 31;
i /= 4;   // well defined loss of precision...   
i /= 4.0; // equally well-defined conversion from floating point to int
1 голос
/ 24 ноября 2011

Плавающие точки могут быть преобразованы в целые числа:

Значение типа с плавающей точкой может быть преобразовано в значение типа целого числа. Конверсионный ствол Кейтс; то есть дробная часть отбрасывается. Поведение не определено, если усеченное значение не может быть представлены в типе назначения.

int f = 42.0;  // Equal to 42, 42 fits into int
int g = 42.1;  // Equal to 42, 42 fits
constexpr float h = 42.7;
int i = h;     // 42

Правила сужения применимы только к спискам инициализаторов.

unsigned char c = { 2.4 }; // narrowing

warning: narrowing conversion of ‘2.3999999999999999e+0’ from ‘double’ to ‘unsigned char’ inside { } [-Wnarrowing]
0 голосов
/ 23 июля 2014

Этот код генерирует ошибки там, где ожидается:

constexpr int a = 255;
unsigned char b = a;      // OK
unsigned char c = a + 1;  // Error... expected

Это приводит к ошибке сужения, поскольку:
1. (a + 1) приводит к значению int r *,
2.не вписывается в допустимый диапазон типа char

int d = 256;
unsigned char e = d;  // Maybe OK because 'd' is not constexpr

Этот код не является сужаемым значением.Это неявное приведение от int к unsigned char.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...