Предупреждение: переполнение при неявном преобразовании констант

В следующей программе строка 5 выдает предупреждение о переполнении, как и ожидалось, но, что удивительно, строка 4 не выдает никаких предупреждений в GCC: http://www.ideone.com/U0BXn

int main()
{
    int i = 256;
    char c1 = i;    //line 4
    char c2 = 256;  //line 5
    return 0;
}

Я думал, что обе строки должны выдавать предупреждение overflow. Или я что-то упускаю?


Тема, которая побудила меня провести этот эксперимент, такова: проверка типов typedef?

Там я сказал следующее (которое я удалил из своего ответа, потому что, когда я его запустил, он не появился, как я ожидал):

//However, you'll get warning for this case:

typedef int  T1;
typedef char T2;

T1 x = 256;     
T2 y = x; //possible overflow warning! (but it doesn't give warning :()

person Nawaz    schedule 23.02.2011    source источник
comment
Какой уровень предупреждения вы установили? VS выдает предупреждения о таких вещах (В ЛЮБОЙ раз, когда вы пытаетесь назначить большой->малый без приведения), но только если вы выкрутите уровень предупреждения до максимума.   -  person Edward Strange    schedule 23.02.2011
comment
@Crazy: я ожидаю предупреждений в обоих случаях. Но GCC не дает в одном случае, даже когда я компилирую его с опцией компилятора -Wall!   -  person Nawaz    schedule 23.02.2011
comment
-Wconversion - это то, что вы хотите добавить. -Wall не интуитивно указывает на включение всех предупреждений:\ gcc.gnu.org/ onlinedocs/gcc/Warning-Options.html   -  person Edward Strange    schedule 23.02.2011
comment
@Crazy: Пожалуйста, опубликуйте это как ответ. Я приму это :D   -  person Nawaz    schedule 23.02.2011


Ответы (4)


-Wall не включает много вариантов. -Wconversion является одним из них и предупреждает об интересующем вас поведении.

См. http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html.

person Edward Strange    schedule 23.02.2011
comment
Это не предупреждало меня в g++ 4.2, поэтому я не упомянул об этом. - person Mark B; 23.02.2011
comment
хм ... Я предполагал, что Наваз проверил, прежде чем просить меня опубликовать ответ. 3.4 тоже не волнует. Основываясь на документации, я, конечно, ожидал этого. int-›char определенно является преобразованием в меньший тип. - person Edward Strange; 23.02.2011
comment
и @Mark: Да, он выдает предупреждение с GCC 4.5.0 - person Nawaz; 23.02.2011

В общем случае присваивания значения int объекту char компилятор не знает, находится ли int за пределами диапазона char.

Посмотрите на фактическое предупреждение более внимательно:

warning: overflow in implicit constant conversion

Именно в этом конкретном случае, когда константа преобразуется в char, компилятор может вас предупредить. Аналогично, если вы изменили объявление i на const:

const int i = 256;

вы также получите предупреждение, потому что значение, присваиваемое c2, является постоянным выражением.

Обратите также внимание, что предупреждение несколько вводит в заблуждение, поскольку преобразование технически не «переполняется». Арифметическое переполнение приводит к неопределенному поведению в C++. Сужающее преобразование (например, int в char, если int имеет больший диапазон, чем char) дает некоторое преобразование, определяемое реализацией.

person James McNellis    schedule 23.02.2011
comment
Но компилятор должен выдать предупреждение, если мы присвоим int char, так как возможна потеря данных! - person Nawaz; 23.02.2011
comment
@Nawaz: Ну, это было бы предупреждение другого рода. Предупреждение, которое вы получаете для c1, говорит о том, что значение выходит за пределы допустимого диапазона для целевого типа. Предупреждение, которое вы хотите получить для c2, похоже на то, что значение может быть выходит за пределы допустимого диапазона для целевого типа. Что касается того, почему gcc не предупреждает об этом, я не знаю (я не использую gcc на регулярной основе). Visual C++ довольно радостно сообщает о предупреждении C4242: «инициализация»: преобразование из «int» в «char», возможная потеря данных. - person James McNellis; 23.02.2011
comment
@Nawaz Я подозреваю, что это потому, что в C int использовался практически в любой функции, где char использовался бы в C++. Таким образом, предупреждение о преобразовании может привести к большому количеству предупреждений о устаревшем коде C. Однако я не могу найти какой-либо параметр стиля -W, чтобы включить такое предупреждение. - person Mark B; 23.02.2011
comment
@MarkB: в C обычно используются типы без знака для представления членов абстрактных алгебраических колец (которые обертывают), а не чисел (что не должно); 8-битный символ без знака будет эквивалентен Z256, каждый элемент которого представляет собой набор целых чисел, эквивалентных по модулю 256. Для каждого целого числа или элемента большего типа кольца степени двойки будет ровно один элемент в результате преобразования может получиться меньший тип кольца степени двойки, но обратное неверно. Таким образом, большие кольца должны неявно преобразовываться в меньшие, но не наоборот. К несчастью... - person supercat; 11.02.2014
comment
@MarkB: ни C, ни C++ не предоставляют никакого способа объявить, следует ли интерпретировать конкретное значение целочисленного типа без знака как число или кольцо. - person supercat; 11.02.2014

Что ж, строка 5 — очевидная ошибка, которую может увидеть любой компилятор, и всегда ошибка. Строка 4 потребует хотя бы некоторого анализа потока данных, чтобы обнаружить ошибку. Возможно, это не сделано с настройками, используемыми на сайте, или, возможно, авторы компилятора не сочли это достаточно важным, чтобы понять это.

person Bo Persson    schedule 23.02.2011
comment
Сразу становится очевидным, что «char x = 256» — это ошибка, если вы знаете, что CHAR_MAX меньше 256. Чтобы понять, что «x = i» всегда является ошибкой, вы должны сначала выяснить, какие значения я мог бы иметь. - person Bo Persson; 23.02.2011
comment
Рассмотрим unsigned short x = 65536. Не сразу становится очевидным, является ли это ошибкой, поскольку размер short может варьироваться от компилятора к компилятору. Технически то же самое верно и для char, хотя размер 8 бит почти универсален. Существуют платформы/компиляторы, для которых char может содержать значение 256. Таким образом, строка 5 не всегда является ошибкой, как вы говорите. - person Ponkadoodle; 01.10.2013
comment
См. этот вопрос для получения дополнительной информации о битовых байтах не-8: на каких платформах есть что-то кроме 8-битных символов? - person SlySven; 30.03.2016

После GCC 4.3 семантика -Wconversion была обновлена ​​для обнаружения неявных преобразований, которые могут изменить значение, но вы также должны включить -Wsign-conversion, потому что в противном случае вы не получите предупреждение о коде, который может изменить знак числа, подлежащего оплате. для приведения между подписанными и беззнаковыми типами.

Вопреки тому, что говорит Безумный Эдди, до версии GCC 4.3 (которая в то время еще не была выпущена) -Wconversion вообще не проверяла наличие проблем, вызванных неявным преобразованием типов и т.п. Скорее, он проверял, будет ли ваша программа вести себя иначе, чем если бы она использовала старые прототипы функций K&R.

Это не только означало, что он не выдавал предупреждения обо всех проблемах неявного преобразования/приведения типов, но также означал, что какой-то хороший код выдавал ненужное предупреждение. И, конечно же, вы не получите ошибки с g++, потому что такие прототипы в любом случае не являются допустимыми C++.

person Anonymous    schedule 18.09.2017