Consider the following code snippet:
// The assigned numbers are random and not relevant
uint16_t val = 2;
uint32_t sum = 4;
sum = val; // point 1
sum /= val; // point 2
- In this operation, is the val automatically cast to
uint32_t
? If not, what is faster- casting it or leaving asuint16_t
? - In this operation, is the val automatically cast to
uint32_t
? If not, what is faster- casting it or leaving asuint16_t
?
Assume the architecture is 16-bit.
CodePudding user response:
In both cases, the value of val
is automatically converted to the larger type uint32_t
. The precise behavior depends on the actual size of int
.
If type
int
has 15 value bits, theval
is converted touint32_t
, preserving the alue, the addition and division are performed usinguint32_t
arithmetics, which operates modulo 232 and the result is stored intosum
.If type
int
has between 16 and 31 value bits,val
is first promoted toint
, preserving its value, then the promoted value is converted touint32_t
, again preserving the value because it is positive, and the operation completes as described above.If type
int
has more than 31 value bits, bothsum
andval
are promoted toint
, preserving the values, the addition and division is performed usingint
signed arithmetics, and the result is converted touint32_t
, modulo 232, for storage intosum
.
For the above example values, the result is the same in all cases, but for the example below, the behavior is undefined on a hypothetical architecture where int
would have 32 value bits:
uint16_t val = 2;
uint32_t sum = 0xffffffff;
sum = val; // signed arithmetic overflow if type `int` has 33 bits
These implicit promotions and conversions are not cast operations, you could add explicit casts such as sum = (uint32_t)val;
but the behavior would be exactly the same and would have no impact on performance.
If the compiler can determine the value of val
at compile time, it will likely compile the expression sum /= val;
into a right shift or a multiplication to avoid a costly division. Dividing an unsigned value by a power of 2 is a cheap right shift operation, if the value is signed and potentially negative, the shift must be adjusted. For other non-zero dividends, a multiplication by 2k/val into a larger type is used.