Сделайте целочисленные типы со знаком C99, определенные в stdint.h демонстрируют четко определенное поведение в случае переполнения?
все операции над" стандартными " знаковыми целочисленными типами в C (short, int, long и т. д.) демонстрируют неопределенное поведение, если они дают результат вне интервала [TYPE_MIN, TYPE_MAX] (где TYPE_MIN, TYPE_MAX-минимальное и максимальное целочисленное значение соответственно. это может быть сохранено определенным целочисленным типом.
согласно стандарту C99, однако, все intN_t
типы должны иметь представление дополнения two:
7.8.11.1 Целочисленные типы точной ширины
1. Имя typedef intN_t обозначает знаковый целочисленный тип с шириной N, без заполнения бит, и представление дополнения two. Таким образом, int8_t обозначает целое число со знаком типа с шириной ровно 8 бит.
значит ли это, что intN_t
типы В C99 демонстрируют четко определенное поведение в случае переполнения целого числа? Например, хорошо ли определен этот код?
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
printf("Minimum 32-bit representable number: %" PRId32 "n", INT32_MAX + 1);
return 0;
}
2 ответов
нет, это не так.
требование для представления дополнения 2 для значений в диапазоне типа не подразумевает ничего о поведении при переполнении.
типы <stdint.h>
- это просто typedefs (псевдонимы) для существующих типов. Добавление typedef не изменяет поведение типа.
пункт 5 раздела 6.5 стандарта C (как C99, так и C11) по-прежнему применяется:
если исключительные условие происходит во время оценки выражение (То есть, если результат не определен математически или не в диапазоне представимых значений для ее типа), поведение неопределено.
это не влияет на неподписанные типы, потому что неподписанные операции не переполняются; они определены для получения обернутого результата, уменьшенного по модулю тип_MAX + 1. За исключением того, что неподписанные типы уже, чем int
звание (подпись) int
, и поэтому может столкнуться с теми же проблемами. Например, это:
unsigned short x = USHRT_MAX;
unsigned short y = USHRT_MAX;
unsigned short z = x * y;
вызывает неопределенное поведение, если short
меньше, чем int
. (Если short
и int
16 и 32 бита, соответственно, потом 65535 * 65535
доходность 4294836225
, что превышает INT_MAX
.)
хотя сохранение значения вне диапазона для подписанного типа хранящиеся в обычно будет хранить нижние биты значения, и перезагрузка значения из памяти подпишет его, многие оптимизации компиляторов могут предположить, что подписанная арифметика не будет переполняться, и эффекты переполнения могут быть непредсказуемыми во многих реальных сценариях. В качестве простого примера, на 16-разрядном DSP, который использует свой 32-разрядный аккумулятор для возвращаемых значений (например, TMS3205X),int16_t foo(int16_t bar) { return bar+1;}
компилятор будет будьте свободны для загрузки bar
, sign-extended, в аккумулятор, добавьте к нему один и вернитесь. Если вызывающий код был, например,long z = foo(32767)
, код может очень хорошо установить z
до 32768, а не -32768.