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.
CodePudding user response:
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 unsigned 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.
CodePudding user response:
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).
CodePudding user response:
My answer was shown to be incorrect by duck. Thanks, duck!
https://stackoverflow.com/a/75203111/2027196
My original answer for future reference:
uintmax_t
andintmax_t
are not guaranteed by the standard to be the same width, but there is no system with a modern C compiler for which they will be different widths. There may not even be a non-modern C compiler for which they will be different widths (asserted without evidence in the same vein as "the sky is blue" type arguments).
The best you can get is that
uintmax_t
andintmax_t
are guaranteed by convention to be the same width. I say "best you can get" but I'd be willing to rely on this guarantee more often than I rely on a compiler perfectly implementing all of its edge-case SFINAE requirements or similar.
Put your
static_assert
at the top of your library (maybe in anassumptions.hpp
file) and then never worry about this problem ever again.
CodePudding user response:
This is from typedef section.
#ifndef _INTMAX_T
#define _INTMAX_T
#ifdef __INTMAX_TYPE__
typedef __INTMAX_TYPE__ intmax_t;
#else
#ifdef __LP64__
typedef long int intmax_t;
#else
typedef long long int intmax_t;
#endif /* __LP64__ */
#endif /* __INTMAX_TYPE__ */
#endif /* _INTMAX_T */
This should answer your question ...