﻿# intmax\_t / uintmax\_t



**Дата**: 24\.07\.2015

Псевдонимы _intmax\_t_ и _uintmax\_t_ — специальные типы данных, определённые в стандартной библиотеке C и C\+\+\. Они обозначают целочисленные типы, которые позволяют отразить значение любого знакового и беззнакового типа соответственно \(C11, [п\.п\. 7\.20\.1\.5](https://open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf)\)\. Типы определены в заголовочном файле [_<stdint\.h\>_](http://www.cplusplus.com/reference/cstdint/) вместе со своими минимальными и максимальными значениями _INTMAX\_MIN_, _INTMAX\_MAX_ и _UINTMAX\_MAX_\. Стандарт C не запрещает реализовывать эти типы через расширенные целочисленные типы\.

Рассмотрим пример, когда могут быть полезны эти типы\. В коде происходит работа с переменной _var_ беззнакового целочисленного типа данных, определённого программистом:

```cpp
mytype_t var;
```

Длина переменной неизвестна или может меняться в зависимости от реализации компилятора\. Задача — корректно вывести значение этой переменной с помощью функции [_printf_](https://en.cppreference.com/w/c/io/fprintf)\. Какой спецификатор конверсии следует использовать? Можно воспользоваться спецификатором _%llu_:

```cpp
printf("%llu", (unsigned long long)var);
```

Однако что делать, если эта переменная принадлежит к типу, который больше, чем _unsigned long long_, и для него не определён спецификатор конверсии? Тут на помощь и приходит тип _uintmax\_t_\.

Модификатором длины для _intmax\_t_ и _uintmax\_t_ в спецификаторе конверсии является буква _j_\. Так как любое беззнаковое целочисленное значение может поместиться в _uintmax\_t_, то приведение к этому типу гарантирует сохранение числа\. Корректный вывод переменной _var_ будет выглядеть так:

```cpp
printf("%ju", (uintmax_t) var);
```

Аналогичная ситуация и с функцией [_scanf_](https://en.cppreference.com/w/c/io/fscanf):

```cpp
mytype_t var;
scanf("%llu", &var);
```

Однако даже такой код может привести к некорректному считыванию числа, если _mytype\_t_ больше, чем _unsigned long long_\. Или к переполнению переменной _var_, если _mytype\_t_ меньше, чем _unsigned long long_\. Корректное считывание можно обеспечить следующим образом:

```cpp
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](https://clang.llvm.org/cxx_status.html#n1988) и [GCC](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49595) не рассматривают _\_\_int128_ и его беззнаковый аналог как расширенные целочисленные типы\. Такое изменение повлекло бы за собой изменение типов _intmax\_t_ и _uintmax\_t_, что нарушило бы [ABI](https://en.wikipedia.org/wiki/Application_binary_interface)\-совместимость с существующими приложениями\.

Представьте, что у вас есть программа, которая использует функцию с параметром _intmax\_t_ в динамической библиотеке\. Если компилятор изменит значение _intmax\_t_ и перекомпилирует программу, то она и библиотека будут ссылаться на разные типы, нарушая бинарную совместимость\.

В конечном итоге _intmax\_t_/_uintmax\_t_ немного не соответствуют целям, описанным для них в стандарте\.

**Список источников**

1. CERT C Coding Standard\. [INT15\-C](https://wiki.sei.cmu.edu/confluence/display/c/int15-c.+use+intmax_t+or+uintmax_t+for+formatted+io+on+programmer-defined+integer+types)\. Use intmax\_t or uintmax\_t for formatted IO on programmer\-defined integer types
1. [Stack Overflow\. What ABI, if any, restricts the size of \[u\]intmax\_t?](https://stackoverflow.com/questions/29927562/what-abi-if-any-restricts-the-size-of-uintmax-t)
1. [Stack Overflow\. Why in g\+\+ std::intmax\_t is not a \_\_int128\_t?](https://stackoverflow.com/questions/21265462/why-in-g-stdintmax-t-is-not-a-int128-t)
1. [Stack Overflow\. Why isn't there int128\_t?](https://stackoverflow.com/questions/29638723/why-isnt-there-int128-t/29638843)