Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would uint32_t be preferred rather than uint_fast32_t?

Tags:

c++

c

int

It seems that uint32_t is much more prevalent than uint_fast32_t (I realise this is anecdotal evidence). That seems counter-intuitive to me, though.

Almost always when I see an implementation use uint32_t, all it really wants is an integer that can hold values up to 4,294,967,295 (usually a much lower bound somewhere between 65,535 and 4,294,967,295).

It seems weird to then use uint32_t, as the 'exactly 32 bits' guarantee is not needed, and the 'fastest available >= 32 bits' guarantee of uint_fast32_t seem to be exactly the right idea. Moreover, while it's usually implemented, uint32_t is not actually guaranteed to exist.

Why, then, would uint32_t be preferred? Is it simply better known or are there technical advantages over the other?

like image 347
Joost Avatar asked Oct 26 '17 16:10

Joost


People also ask

What is the difference between uint32 and uint32_t?

typedef unsigned integer type uint32_t; // optional //... } uint32 is not, it's a shortcut provided by some compilers (probably as typedef uint32_t uint32 ) for ease of use. More likely as a typedef for something that was known to be an unsigned 32 bit integer at a time before <cstdint> was standard.

What is a uint32_t?

uint32_t is a numeric type that guarantees 32 bits. The value is unsigned, meaning that the range of values goes from 0 to 232 - 1. This. uint32_t* ptr; declares a pointer of type uint32_t* , but the pointer is uninitialized, that is, the pointer does not point to anywhere in particular.

What is the data type and range of uint32_t?

The UInt32 value type represents unsigned integers with values ranging from 0 to 4,294,967,295.


2 Answers

uint32_t is guaranteed to have nearly the same properties on any platform that supports it.1

uint_fast32_t has very little guarantees about how it behaves on different systems in comparison.

If you switch to a platform where uint_fast32_t has a different size, all code that uses uint_fast32_t has to be retested and validated. All stability assumptions are going to be out the window. The entire system is going to work differently.

When writing your code, you may not even have access to a uint_fast32_t system that isn't 32 bits in size.

uint32_t won't work differently (see footnote).

Correctness is more important than speed. Premature correctness is thus a better plan than premature optimization.

In the event I was writing code for systems where uint_fast32_t was 64 or more bits, I might test my code for both cases and use it. Barring both need and opportunity, doing so is a bad plan.

Finally, uint_fast32_t when you are storing it for any length of time or number of instances can be slower than uint32 simply due to cache size issues and memory bandwidth. Todays computers are far more often memory-bound than CPU bound, and uint_fast32_t could be faster in isolation but not after you account for memory overhead.


1 As @chux has noted in a comment, if unsigned is larger than uint32_t, arithmetic on uint32_t goes through the usual integer promotions, and if not, it stays as uint32_t. This can cause bugs. Nothing is ever perfect.

like image 171
Yakk - Adam Nevraumont Avatar answered Oct 13 '22 06:10

Yakk - Adam Nevraumont


Why do many people use uint32_t rather than uint32_fast_t?

Note: Mis-named uint32_fast_t should be uint_fast32_t.

uint32_t has a tighter specification than uint_fast32_t and so makes for more consistent functionality.


uint32_t pros:

  • Various algorithms specify this type. IMO - best reason to use.
  • Exact width and range known.
  • Arrays of this type incur no waste.
  • unsigned integer math with its overflow is more predictable.
  • Closer match in range and math of other languages' 32-bit types.
  • Never padded.

uint32_t cons:

  • Not always available (yet this is rare in 2018).
    E.g.: Platforms lacking 8/16/32-bit integers (9/18/36-bit, others).
    E.g.: Platforms using non-2's complement. old 2200

uint_fast32_t pros:

  • Always available.
    This always allow all platforms, new and old, to use fast/minimum types.
  • "Fastest" type that support 32-bit range.

uint_fast32_t cons:

  • Range is only minimally known. Example, it could be a 64-bit type.
  • Arrays of this type may be wasteful in memory.
  • All answers (mine too at first), the post and comments used the wrong name uint32_fast_t. Looks like many just don't need and use this type. We didn't even use the right name!
  • Padding possible - (rare).
  • In select cases, the "fastest" type may really be another type. So uint_fast32_t is only a 1st order approximation.

In the end, what is best depends on the coding goal. Unless coding for very wide portability or some niched performance function, use uint32_t.


There is another issue when using these types that comes into play: their rank compared to int/unsigned

Presumably uint_fastN_t could be the rank of unsigned. This is not specified, but a certain and testable condition.

Thus, uintN_t is more likely than uint_fastN_t to be narrower the unsigned. This means that code that uses uintN_t math is more likely subject to integer promotions than uint_fastN_t when concerning portability.

With this concern: portability advantage uint_fastN_t with select math operations.


Side note about int32_t rather than int_fast32_t: On rare machines, INT_FAST32_MIN may be -2,147,483,647 and not -2,147,483,648. The larger point: (u)intN_t types are tightly specified and lead to portable code.

like image 24
chux - Reinstate Monica Avatar answered Oct 13 '22 05:10

chux - Reinstate Monica