Обладают ли целочисленные типы со знаком C99, определенные в stdint.h, хорошо определенным поведением в случае переполнения? - PullRequest
11 голосов
/ 20 февраля 2012

Все операции со «стандартными» знаковыми целочисленными типами в C (short, int, long и т. Д.) Демонстрируют неопределенное поведение, если они дают результат вне интервала [TYPE_MIN, TYPE_MAX] (где TYPE_MIN, TYPE_MAX являются минимальными и максимальное целочисленное значение соответственно, которое может быть сохранено конкретным целочисленным типом.

Однако в соответствии со стандартом C99 все типы intN_t должны иметь представление в виде дополнения до двух:

7.8.11.1 Целочисленные типы точной ширины
1. Имя typedef intN_t обозначает целочисленный тип со знаком с шириной N, без заполнения биты и представление дополнения до двух. Таким образом, 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 ]

12 голосов
/ 20 февраля 2012

Нет, это не так.

Требование представления в виде дополнения 2 для значений в пределах диапазона типа ничего не подразумевает в поведении при переполнении.

Типыв <stdint.h> - просто typedefs (псевдонимы) для существующих типов.Добавление typedef не меняет поведения типа.

Раздел 6.5, параграф 5 стандарта C (как C99, так и C11) по-прежнему применяется:

Если исключительное условие происходит во время вычисления выражения (то есть, если результат не определен математически или не находится в диапазоне представимых значений для его типа), поведение не определено.

Это нене влияет на неподписанные типы, потому что неподписанные операции не переполняются;они определены так, чтобы получить свернутый результат, уменьшенный по модулю TYPE _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.)

4 голосов
/ 11 мая 2013

Хотя при сохранении значения вне диапазона для типа со знаком , хранящегося в памяти , обычно хранятся младшие биты значения, а перезагрузка значения из памяти расширяет его, многие компиляторыОптимизация может предполагать, что подписанная арифметика не будет переполнена, и последствия переполнения могут быть непредсказуемыми во многих реальных сценариях.В качестве простого примера, на 16-разрядном DSP, который использует один 32-разрядный аккумулятор для возвращаемых значений (например, TMS3205X), int16_t foo(int16_t bar) { return bar+1;} компилятор может свободно загружать bar со знаком расширения в аккумулятор, добавитьодин к нему, и вернуться.Если бы вызывающим кодом было, например, long z = foo(32767), код вполне мог бы установить z на 32768 вместо -32768.

...