Стандарт C явно определяет целочисленное переполнение со знаком как неопределенное поведение. Тем не менее, большинство ЦП реализуют знаковую арифметику с определенной семантикой для переполнения (за исключением, может быть, переполнения деления: x/0
и INT_MIN / -1
).
Авторы компиляторов воспользовались неопределенностью таких переполнений, чтобы добавить более агрессивные оптимизации, которые имеют тенденцию разрушать унаследованный код очень тонкими способами. Например, этот код мог работать на старых компиляторах, но больше не работает на текущих версиях gcc
и clang
:
/* Tncrement a by a value in 0..255, clamp a to positive integers.
The code relies on 32-bit wrap-around, but the C Standard makes
signed integer overflow undefined behavior, so sum_max can now
return values less than a. There are Standard compliant ways to
implement this, but legacy code is what it is... */
int sum_max(int a, unsigned char b) {
int res = a + b;
return (res >= a) ? res : INT_MAX;
}
Есть ли веские доказательства того, что эти оптимизации стоят того? Существуют ли сравнительные исследования, документирующие фактические улучшения на реальных примерах или даже на классических тестах?
Я придумал этот вопрос, наблюдая за этим: c++ Теперь 2018: Джон Регер "Закрытие Keynote: неопределенное поведение и оптимизация компилятора"
Я отмечаю c и c++, так как проблема одинакова на обоих языках, но ответы могут быть разными.