Предполагает ли компилятор C добавление целых чисел со знаком коммутативно? - PullRequest
0 голосов
/ 09 сентября 2018

Я пытаюсь проверить, не переполнится ли подписанное дополнение. Как правило, чтобы проверить, если

int a + int b

переполнится (a и b оба положительные), я проверяю, если

if (a > INT_MAX - b)

Но теперь я хочу проверить, если

int a + int b - int c

переполнится. Я знаю, что a, b и c положительны, а b> = c, поэтому я делаю следующую проверку:

if (a > INT_MAX - b + c)

Теперь мой вопрос, может ли компилятор переписать

INT_MAX - b + c     to     INT_MAX + c - b   ?

Меня беспокоит то, что сначала он выполнит INT_MAX + c, который может переполниться и привести к неопределенному поведению.

Ответы [ 3 ]

0 голосов
/ 09 сентября 2018

Ошибочно думать о том, что делает «компилятор», рассуждая о неопределенном поведении. Компилятор прозрачный. Поведение находится в вашем коде, а не в компиляторе. Вы должны спросить "что означает мой код INT_MAX - b + c означает ? Может ли он переполниться? Ответ никогда не в" компиляторе ", а в стандарте.

Стандарт требует только, чтобы отдельные операции, которые появляются в вашей программе , не переполнялись. Он никогда не говорит ничего о каких-либо переписанных выражениях, которые явно не появляются в вашей программе. INT_MAX - b + c в вашей программе и эквивалентно (INT_MAX - b) + c. Таким образом, требуется, чтобы (INT_MAX - b) не переполнялся, а затем результат, добавленный к c, не переполнялся. INT_MAX + c - b не отображается в вашей программе, поэтому вам не следует об этом беспокоиться.

Если компилятор переписывает ваше выражение каким-либо образом, он должен убедиться, что переписанное выражение имеет то же видимое поведение, что и у вас, согласно правилу как если бы . Поэтому, если он заменяет INT_MAX - b + c на INT_MAX + c - b, он должен убедиться, что переполнение либо не происходит, либо решается прозрачно (например, игнорируется аппаратными средствами).

0 голосов
/ 09 сентября 2018

Выражение a - b + c эквивалентно (a - b) + c. Это закодировано в грамматике для языка, наиболее релевантное предложение здесь 6.5.6: 1 (но, конечно, вам нужно взглянуть на всю грамматику, чтобы понять смысл этого предложения).

      additive-expression:
             multiplicative-expression
             additive-expression + multiplicative-expression
             additive-expression - multiplicative-expression

Когда сталкивается с a - b + c, компилятор может только проанализировать его как сумму аддитивного выражения a - b и мультипликативного выражения c. Нет другого правила, которое может применяться. Так что a - b + c - это сумма a - b, что бы это ни было, и c.

Компилятор может генерировать ассемблерный код, который он считает наиболее подходящим для предоставленного вами исходного кода, но он должен сохранять значение программы. Если вы написали исходный код, который был определен для a = INT_MAX, b = 2 и c = 1, то код сборки должен предоставить правильный ответ для этих значений. Если компилятор решит переупорядочить операции, он будет делать это только таким образом, чтобы сохранить смысл, например, потому что он знает, что инструкции по сборке для целевой архитектуры дают два результата комплемента и могут быть переупорядочены для получения того же результата.

0 голосов
/ 09 сентября 2018

Ну, мы можем предположить, что нет.

Но "Стандарт языка C не определяет приоритет оператора."

Но ябудет добавлено в скобках, потому что даже если есть небольшой шанс приоритет будет испорчен.

Цитата из https://stackoverflow.com/a/2722316/3268169:

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

приводит глупый аргумент.

Читаемость должна быть улучшена, если этопроблема.

...