Как известно, целочисленное переполнение со знаком - это неопределенное поведение . Но в cstdint
документации по C ++ 11 есть кое-что интересное :
целочисленный тип со знаком шириной ровно 8, 16, 32 и 64 бита соответственно без битов заполнения и с использованием дополнения до 2 для отрицательных значений (предоставляется только в том случае, если реализация напрямую поддерживает тип)
И вот мой вопрос: так как стандарт прямо говорит , что для int8_t
, int16_t
, int32_t
иint64_t
отрицательных чисел 2 - х комплемент, по - прежнему переполнение этих типов неопределенного поведения?
редактировать Я проверил стандарты C ++ 11 и C11, и вот что я нашел:
С ++ 11, §18.4.1:
Заголовок определяет все функции, типы и макросы так же, как 7.20 в стандарте C.
C11, §7.20.1.1:
Имя typedef
intN_t
обозначает целочисленный тип со знаком шириной N, без битов заполнения и представление с дополнением до двух. Таким образом,int8_t
обозначает такой знаковый целочисленный тип шириной ровно 8 бит.
Ответы:
Да. Согласно параграфу 5/4 стандарта C ++ 11 (в отношении любого выражения в целом):
Тот факт, что для этих типов со знаком используется представление с двумя дополнениями, не означает, что арифметика по модулю 2 ^ n используется при оценке выражений этих типов.
Что касается беззнаковой арифметики, с другой стороны, Стандарт явно указывает, что (Параграф 3.9.1 / 4):
Это означает, что результат беззнаковой арифметической операции всегда " математически определен ", и результат всегда находится в пределах представимого диапазона; следовательно, 5/4 не применяется. Сноска 46 объясняет это:
источник
Просто потому, что тип определен для использования представления с двумя дополнениями, это не означает, что арифметическое переполнение в этом типе становится определенным.
Неопределенное поведение подписанного арифметического переполнения используется для оптимизации; например, компилятор может предположить, что если,
a > b
тоa + 1 > b
также; это не выполняется в беззнаковой арифметике, где вторая проверка должна быть выполнена из-за возможности, что онаa + 1
может завершиться0
. Кроме того, некоторые платформы могут генерировать сигнал прерывания при арифметическом переполнении (см., Например, http://www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.html ); стандарт по-прежнему допускает это.источник
abs
. Для тех операций, когда он работает, не требуется больше инструкций, чем при подписанной артметике.(int)(x+y)>z
будет сравнивать завернутый результат), а также позволит программистам писатьx+y>z
в тех случаях, когда было бы приемлемо для кода выдавать 0 или 1 в случае переполнения при условии, что у него нет других побочных эффектов . Если равным образом приемлемым результатом будет либо 0, либо 1, позволяя программисту писать это, а не любую из них,(long)x+y>z
или(int)((unsigned)x+y)>z
позволит компиляторам выбрать ту из последних функций, которая будет дешевле в любом данном контексте [каждая из них будет дешевле в некоторых случаях].Готов поспорить.
Из стандартной документации (стр.4 и 5):
источник