Starting with the 1999 edition, the ISO C standard defines a standard header <stdint.h>
which defines, among other things, the typedefs intmax_t
and uintmax_t
. These designate, respectively, "a (signed|unsigned) integer type capable of representing any value of any (signed|unsigned) integer type".
For example, if, as is typical, the widest signed and unsigned integer types are long long int
and unsigned long long int
, both of which are typically 64 bits, then intmax_t
and uintmax_t
might be defined in <stdint.h>
as follows:
typedef long long int intmax_t;
typedef unsigned long long int uintmax_t;
There is a limited set of predefined signed and unsigned integer types, ranging from signed
, unsigned
, and plain char
up to signed
and unsigned
long long int
.
C99 and C11 also permit implementations to define extended integer types, which are distinct from any of the standard types and have names that are implementation-defined keywords.
Both gcc and clang, on some but not all targets, support types __int128
and unsigned __int128
. These act like 128-bit integer types, but they are not treated as extended integer types, and the documentation for both compilers states that they do not support any extended integer types. Because these are not integer types as the Standard defines the term, the typedefs intmax_t
and uintmax_t
are for 64-bit types, not 128-bit types.
None of this violates the C standard (implementations are not required to have any extended integer types, and they're permitted to have arbitrary extensions as long as they don't break any strictly conforming programs). But it seems to me that it would make perfect sense for __int128
and unsigned __int128
to be treated as extended integer types, and for intmax_t
and uintmax_t
to be 128-bit types.
The rationale for not doing this is that changing the size of intmax_t
and uintmax_t
would be "an ABI-incompatible change".
The Clang C++ status page says, in footnote (5):
No compiler changes are required for an implementation such as Clang that does not provide any extended integer types.
__int128
is not treated as an extended integer type, because changingintmax_t
would be an ABI-incompatible change.
(Yes, this primarily discusses C++, but the rules are the same as for C.)
In a gcc bug report, the claim is made that:
sizeof(intmax_t)
is fixed by various LP64 ABIs and cannot be changed
In both cases, no reference is given for this claim.
An x86_64 ABI document titled "System V Application Binary Interface, AMD64 Architecture Processor Supplement, Draft Version 0.99.6" does not mention intmax_t
or uintmax_t
, or even the <stdint.h>
header. It does specify sizes and alignments for the predefined integer types (in Figure 3.1).
Finally, my question: Is the claim that the sizes of intmax_t
and uintmax_t
restricted by an ABI valid? If so, what ABI imposes such a requirement? (And, incidentally, why?)
(In my opinion, such a requirement, if it exists, is unwise. It defeats the purpose of the C standard's permission to define extended integer types, and the intended meaning of intmax_t
and uintmax_t
. It makes it much more difficult to use 128-bit integer types effectively on systems that support them, while falling back to narrower types on other systems.)
Update: In N2303, titled "intmax t, a way out", Jens Gustedt proposes tweaking the definitions of [u]intmax_t
to permit adding extended integer types wider than long long
without having to update [u]intmax_t
. For example, intmax_t
might be a typedef for long long
, but the implementation could still provide, say, __int128
as an extended integer type.
References:
- N1256, a draft of the C99 standard
- N1570, a draft of the C11 standard
- N2303, a proposal by Jens Gustedt
- System V AMD64 ABI
intmax_t
be an extended precision type that requires carry/borrow for add/sub, and even more complexity for mul/div, would lead to more bloated code than necessary. Basically I'm saying that some programmers may assumeintmax_t
to be no wider than the target can efficiently support. This is not a good argument, sinceintmax_t
is 64bit on most 32bit machines. It would be nice if there was anint128_t
, butintmax_t
can't change on existing platforms without breaking backwards compat. – Mismanage