Дата: 24.07.2015
Псевдонимы intmax_t и uintmax_t — специальные типы данных, определённые в стандартной библиотеке C и C++. Они обозначают целочисленные типы, которые позволяют отразить значение любого знакового и беззнакового типа соответственно (C11, п.п. 7.20.1.5). Типы определены в заголовочном файле <stdint.h> вместе со своими минимальными и максимальными значениями INTMAX_MIN, INTMAX_MAX и UINTMAX_MAX. Стандарт C не запрещает реализовывать эти типы через расширенные целочисленные типы.
Рассмотрим пример, когда могут быть полезны эти типы. В коде происходит работа с переменной var беззнакового целочисленного типа данных, определённого программистом:
mytype_t var;
Длина переменной неизвестна или может меняться в зависимости от реализации компилятора. Задача — корректно вывести значение этой переменной с помощью функции printf. Какой спецификатор конверсии следует использовать? Можно воспользоваться спецификатором %llu:
printf("%llu", (unsigned long long)var);
Однако что делать, если эта переменная принадлежит к типу, который больше, чем unsigned long long, и для него не определён спецификатор конверсии? Тут на помощь и приходит тип uintmax_t.
Модификатором длины для intmax_t и uintmax_t в спецификаторе конверсии является буква j. Так как любое беззнаковое целочисленное значение может поместиться в uintmax_t, то приведение к этому типу гарантирует сохранение числа. Корректный вывод переменной var будет выглядеть так:
printf("%ju", (uintmax_t) var);
Аналогичная ситуация и с функцией scanf:
mytype_t var;
scanf("%llu", &var);
Однако даже такой код может привести к некорректному считыванию числа, если mytype_t больше, чем unsigned long long. Или к переполнению переменной var, если mytype_t меньше, чем unsigned long long. Корректное считывание можно обеспечить следующим образом:
mytype_t var;
uintmax_t temp;
scanf("%ju", &temp);
if(temp <= MYTYPE_MAX)
var = temp;
Примечание об __int128 и его беззнаковом аналоге. В случае компиляторов Clang или GCC, типы intmax_t и uintmax_t определены как long long и unsigned long long соответственно. Дело в том, что Clang и GCC не рассматривают __int128 и его беззнаковый аналог как расширенные целочисленные типы. Такое изменение повлекло бы за собой изменение типов intmax_t и uintmax_t, что нарушило бы ABI-совместимость с существующими приложениями.
Представьте, что у вас есть программа, которая использует функцию с параметром intmax_t в динамической библиотеке. Если компилятор изменит значение intmax_t и перекомпилирует программу, то она и библиотека будут ссылаться на разные типы, нарушая бинарную совместимость.
В конечном итоге intmax_t/uintmax_t немного не соответствуют целям, описанным для них в стандарте.
Список источников
0