Integer and floating point rank and promotion rules in C and C++
I'd like to take a stab at this to summarize the rules so I can quickly reference them. I've fully studied the question and both of the other two answers here, including the main one by @Lundin. If you want more examples beyond the ones below, go study that answer in detail as well, while referencing my "rules" and "promotion flow" summaries below.
I've also written my own example and demo code here: integer_promotion_overflow_underflow_undefined_behavior.c.
Despite normally being incredibly verbose myself, I'm going to try to keep this a short summary, since the other two answers plus my test code already have sufficient detail via their necessary verbosity.
Integer and variable promotion quick reference guide and summary
3 simple rules
- For any operation where multiple operands (input variables) are involved (ex: mathematical operations, comparisons, or ternary), the variables are automatically implicitly promoted as required to the required variable type before the operation is performed.
- Therefore, you must manually, explicitly cast the output to any desired type you desire if you do not want it to be implicitly chosen for you. See the example below.
- All types smaller than
int
(int32_t
on my 64-bit Linux system) are "small types". They cannot be used in ANY operation. So, if all input variables are "small types", they are ALL first automatically implicitly promoted toint
(int32_t
on my 64-bit Linux system) before performing the operation. - Otherwise, if at least one of the input types is
int
or larger, the other, smaller input type or types are automatically implicitly promoted to this largest-input-type's type.
Example
Example: with this code:
uint8_t x = 0;uint8_t y = 1;
...if you do x - y
, they first get implicitly promoted to int
(which is int32_t
on my 64-bitsystem), and you end up with this: (int)x - (int)y
, which results in an int
type with value-1
, rather than a uint8_t
type of value 255
. To get the desired 255
result, manuallycast the result back to uint8_t
, by doing this: (uint8_t)(x - y)
.
Promotion flow
The promotion rules are as follows. Promotion from smallest to largest types is as follows.
Read "-->
" as "gets promoted to".
The types in square brackets (ex: [int8_t]
) are the typical "fixed-width integer types" for the given standard type on a typical 64-bit Unix (Linux or Mac) architecture. See, for example:
- https://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)IntegerTypes.html
- https://www.ibm.com/docs/en/ibm-mq/7.5?topic=platforms-standard-data-types
- And even better, test it for yourself on your machine by running my code here!: stdint_sizes.c from my eRCaGuy_hello_world repo.
1. For integer types in 64-bit x86-64 architecture CPUs
Note: "small types" = bool
(_Bool
), char [int8_t]
, unsigned char [uint8_t]
, short [int16_t]
, unsigned short [uint16_t]
.
SMALL TYPES: bool
(_Bool
), char [int8_t]
, unsigned char [uint8_t]
, short [int16_t]
, unsigned short [uint16_t]
--> int [int32_t]
--> unsigned int [uint32_t]
--> long int [int64_t]
--> unsigned long int [uint64_t]
--> long long int [int64_t]
--> unsigned long long int [uint64_t]
Pointers (ex: void*
) and size_t
are both 64-bits, so I imagine they fit into the uint64_t
category above.
2. For floating point types
float [32-bits]
--> double [64-bits]
--> long double [128-bits]
See also
- https://cppinsights.io/ - a very useful tool which expands your C++ code into exactly what the compiler sees, including after applying all automatic implicit type promotion rules in the compiler.
- Ex: see my code from my answer here in CPPInsights.io here: https://cppinsights.io/s/bfc425f6 --> then click the play button to convert and expand it into what the compiler sees, including after applying all automatic implicit type promotion rules.