Почему gcc не создает предупреждение о несоответствии типа для int и char?

Почему компиляция следующего кода в gcc не приводит к предупреждению о несоответствии типа? -1 имеет тип int , а f() ожидает тип char :

 void f(char c) {} int main(void) { f(-1); return 0; } 

Даже если мы явно укажем типы, нет предупреждения:

 void f(unsigned char c) {} int main(void) { f((signed int)-1); return 0; } 

Что любопытно: если мы укажем значение вне диапазона, выводится предупреждение:

 void f(char c) {} int main(void) { f(65535); return 0; } 

warning: overflow in implicit constant conversion

Версия gcc 6.1.1

Похоже на недостаток в опции предупреждения gcc’s Wconversion.

Если этот параметр включен, этот параметр предупреждения предупреждает о назначении:

 int i = c; //where c is of type char 

и передача переменных в функции:

 f(i); //where i is of type int 

но не предупреждает о передаче целочисленных литералов:

 f(-1); //where -1 is of type int 

Согласно стандарту C, последний пример также должен содержать предупреждение.

Gcc достаточно умен, чтобы распознавать целочисленный литерал в виде символа и не предупреждает, тогда как если используется значение, которое не подходит, оно предупреждает.

Это разумное поведение, хотя педантичный пользователь будет исключать предупреждение в последнем примере, которое должно быть отключено приложением cast to type.

Gcc на самом деле включает предупреждение, предупреждающее, когда знак целочисленного типа изменяется посредством неявного преобразования. Используйте: -Wsign-conversion, и вы получите предупреждение для второго примера.

int может быть преобразован в char . В int разрешено преобразовывать в char как в C, так и в C ++.

Из стандарта C11:

6.3.1.3 Целочисленные и беззнаковые целые числа

1 Когда значение с целым типом преобразуется в другой целочисленный тип, отличный от _Bool , если значение может быть представлено новым типом, оно не изменяется.

2 В противном случае, если новый тип без знака, значение преобразуется путем многократного добавления или вычитания более одного значения, которое может быть представлено в новом типе, пока значение не будет в диапазоне нового типа.

3 В противном случае новый тип подписан и значение не может быть представлено в нем; либо результат определяется реализацией, либо генерируется сигнал, определяемый реализацией.

Из стандарта C ++ 11:

4.7 Интегральные преобразования

1 Prvalue целочисленного типа может быть преобразовано в prvalue другого целочисленного типа. Prvalue неперечисленного типа enums может быть преобразована в prvalue целочисленного типа.

2 Если тип назначения не указан, результирующее значение представляет собой наименьшее целое число без знака, сравнимое с исходным целым числом …

3 Если тип назначения подписан, значение не изменяется, если оно может быть представлено в типе адресата (и ширине битового поля); в противном случае значение определяется реализацией.

Если char является подписанным типом, он может легко удерживать значение -1. Следовательно, поведение предсказуемо. Интегральное значение c в f будет равным -1. Когда используется unsigned char , значение c будет значением, определяемым реализацией, но оно по-прежнему разрешено в соответствии с обоими стандартами.