Сделайте целочисленные типы со знаком 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.