I need to know if intmax_t
is always "the same type" as uintmax_t
except using two's complement instead of unsigned value.
Or putting this in formal terms, will the code below always compile in a standard-compliant compiler?
#include <cstdint>
// The important assertion:
static_assert(sizeof(std::uintmax_t) == sizeof(std::intmax_t));
// Less important assertions:
static_assert(UINTMAX_MAX == static_cast<std::uintmax_t>(INTMAX_MAX) * 2 + 1);
static_assert(-static_cast<std::intmax_t>(UINTMAX_MAX / 2) - 1 == INTMAX_MIN);
I'm particularly interested in C++17.
I know that C++20 is the first version of the standard that enforces two's complement but the size of the variable is more important to me than the representation.
Yes, uintmax_t
is guaranteed to be the unsigned counterpart of intmax_t
.
From the C standard (N1570 7.20.1):
When typedef names differing only in the absence or presence of the initial
u
are defined, they shall denote corresponding signed and unsigned types as described in 6.2.5; an implementation providing one of these corresponding types shall also provide the other.
(C++ simply refers to C for the description of C standard library headers.)
6.2.5 p6:
For each of the signed integer types, there is a corresponding (but different) unsigned integer type (designated with the keyword
unsigned
) that uses the same amount of storage (including sign information) and has the same alignment requirements.
C++ is similar to C in this regard ([basic.fundamental]/3):
For each of the standard signed integer types, there exists a corresponding (but different) standard unsigned integer type [...] which occupies the same amount of storage and has the same alignment requirements as the corresponding signed integer type; that is, each signed integer type has the same object representation as its corresponding unsigned integer type. Likewise, for each of the extended signed integer types there exists a corresponding extended unsigned integer type with the same amount of storage and alignment requirements.
Which means intmax_t
and uintmax_t
always have the same size.
However, it is not guaranteed that the other two assertions will hold (prior to C++20/C23).
From the comments/title, it seems you're asking if they're required to be the same size; in which case, the short answer is yes ... long answer ... kind of :)
Quote from [basic.fundamental]/3
(C++17 draft N4713)
For each of the standard signed integer types, there exists a corresponding (but different) standard unsigned integer type: “unsigned char”, “unsigned short int”, “unsigned int”, “unsigned long int”, and “unsigned long long int”, each of which occupies the same amount of storage and has the same alignment requirements as its corresponding signed integer type.
(emphasis mine)
This guarantees that the unsigned versions take up the same size as their signed equivalents.
That being said, the standard [cstdint.syn]
only states:
using intmax_t = signed integer type;
using uintmax_t = unsigned integer type;
The [basic.fundamental]/2
states
The standard and extended signed integer types are collectively called signed integer types.
and The [basic.fundamental]/3
states
The standard and extended unsigned integer types are collectively called unsigned integer types
So, technically, a compiler does not have to implement them as the same type, since that's an implementation detail; practically speaking though, they'd be the same.
As noted by duck, the C standard does indicate that there must be corresponding versions between types with u
and no u
prefix. The C standard is referenced via [cstdint.syn]/2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With