Тест ENV
- Linux
- Intel x86-64 GCC 8.2.1
- Флаги включены:
-Wextra -Wall -Wfloat-equal -Wundef -Wshadow -Winit-self -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wstrict-overflow=5 -Wwrite-strings -Waggregate-return -Wcast-qual -Wswitch-default -Wswitch-enum -Wconversion -Wunreachable-code -Wformat=2 -pedantic -pedantic-errors -Werror-implicit-function-declaration -Wformat-security -fstrict-overflow
sizeof(long)
равно 8. sizeof(int)
равно 4.
Пример 1, получено предупреждение, хорошо:
long x = 2147483647 * 3;
Пример 2, без предупреждения, не хорошо:
long x = 2147483647U * 3U; // Suffix U
или
unsigned int a = 2147483647;
unsigned int b = 3;
long x = a*b;
Пример 3, без предупреждения, но работает, как ожидалось:
long x = 2147483647L * 3L; // Suffix L
В примере 2 я знаючто это обход, а не целочисленное переполнение, но это те случаи, о которых компилятор не может предупредить?
Из стандарта:
(6.3.1.8)
В противном случае целочисленные преобразования выполняются для обоих операндов.Затем к продвигаемым операндам применяются следующие правила:
Если оба операнда имеют одинаковый тип, дальнейшее преобразование не требуется.В противном случае, если оба операнда имеют целочисленные типы со знаком или оба имеют целочисленные типы без знака, операнд с типом меньшего целого ранга преобразования преобразуется в тип операнда с большим рангом.
В противном случае, если операнд, которыйимеет целочисленный тип без знака имеет ранг больше или равен рангу типа другого операнда, тогда операнд с целочисленным типом со знаком преобразуется в тип операнда с целочисленным типом без знака.
В противном случае, если тип операнда с целым типом со знаком может представлять все значения типа операнда с целым типом без знака, то операнд с целым типом без знака преобразуется в тип операндас целым типом со знаком.
В противном случае оба операнда преобразуются в целочисленный тип без знака, соответствующий типу операнда с целым типом со знаком.
(6.5):
Если во время вычисления выражения возникает исключительное условие (то есть, если результат не определен математически или не находится в диапазоне представимых значений для его (типа), поведение не определено.
Начато использование Clang с флагом -fsanitize=unsigned-integer-overflow
, который очень помогает с нежелательными значениями при переносе. Это не целочисленное переполнение, но не предполагаемое значение. Поскольку GCC до сих пор не поддерживаетпредупреждение как это, переходя к Clang.