Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is `uint_fast32_t` guaranteed to be at least as wide as `int`?

The C standard specifies that integer operands smaller than int will be promoted to int before any arithmetic operations are performed upon them. As a consequence, operations upon two unsigned values which are smaller than int will be performed with signed rather than unsigned math. In cases where it is important to ensure that operation on 32-bit operands will be performed using unsigned math (e.g. multiplying two numbers whose product could exceed 2⁶³) will use of the type uint_fast32_t be guaranteed by any standard to yield unsigned semantics without any Undefined Behavior? If not, is there any other unsigned type which is guaranteed to be at least 32 bits and at least as large as int?

like image 848
supercat Avatar asked Mar 21 '23 05:03

supercat


2 Answers

No, it's not. In any case, I would advise against using the [u]int_fastN_t types at all. On real-world systems they're misdefined; for example, uint_fast32_t is usually defined as a 64-bit type on x86_64, despite 64-bit operations being at best (addition, subtraction, logical ops) identical speed to 32-bit ones and at worst much slower (division, and loads/stores since you use twice as many cache lines).

like image 169
R.. GitHub STOP HELPING ICE Avatar answered Apr 01 '23 00:04

R.. GitHub STOP HELPING ICE


The C standard only requires int to be at least 16 bits and places no upper bound on its width, so uint_fast32_t could be narrower than int, or the same width, or wider.

For example, a conforming implementation could make int 64 bits and uint_fast32_t a typedef for a 32-bit unsigned short. Or, conversely, int could be 16 bits and uint_fast32_t, as the name implies, must be at least 32 bits.

One interesting consequence is that this:

uint_fast32_t x = UINT_FAST32_MAX;
uint_fast32_t y = UINT_FAST32_MAX;
x * y;

could overflow, resulting in undefined behavior. For example, if short is 32 bits and int is 64 bits, then uint_fast32_t could be a typedef for unsigned short, which would promote to signed int before being multiplied; the result, which is nearly 264, is too big to be represented as an int.

POSIX requires int and unsigned int to be at least 32 bits, but the answer to your question doesn't change even for POSIX-compliant implementations. uint_fast32_t and int could still be either 32 and 64 bits respectively, or 64 and 32 bits. (The latter would imply that a 64-bit type is faster than int, which is odd given that int is supposed to have the "natural size suggested by the architecture", but it's permitted.)

In practice, most compiler implementers will tend to try to cover 8, 16, 32, and 64-bit integers with the predefined types, which is possible only of int is no wider than 32 bits. The only compilers I've seen that don't follow this were for Cray vector machines. (Extended integer types could work around this, but I haven't seen a compiler that takes advantage of that.)

If not, is there any other unsigned type which is guaranteed to be at least 32 bits and at least as large as int?

Yes, unsigned long (and unsigned long long which is at least 64 bits.)

like image 31
Keith Thompson Avatar answered Mar 31 '23 22:03

Keith Thompson