Consider the following piece of C code:
#include <stdint.h>
uint32_t inc(uint16_t x) {
return x+1;
}
When compiled with gcc-4.4.3 with flags -std=c99 -march=core2 -msse4.1 -O2 -pipe -Wall on a pure x86_64 system, it produces
movzwl %di,%eax
inc %eax
retq
Now, unsigned overflow is predicted in C. I do not know much about x86_64 assembly, but as far as I can see the 16bit argument register is being moved to a 32bit register, which is incremented and returned. My question is, what if x == UINT16_MAX. An overflow would occur and the standard dictates x+1==0, right? However, given %eax is a 32bit register, it now contains UINT16_MAX+1, which is not correct.
This lets me connect one question here: is there a portable way to disable unsigned overflow in C so that the compiler can assume the upper bits of a small variable stored in a large register will always be 0 (so it needs not clear them)? If not (or if the solution is syntactically nasty), is there a way to do it at least in GCC?
Thank you very much for your time.
No, C types are subject to default promotions. Assuming uint16_t
has lower conversion rank than int
, it will be promoted to int
and the addition will be carried out as an int
, then converted to uint32_t
when returned.
As for your related question at the end, I don't quite follow what you want.
Use a coding style that does not use compiler intermediaries for calculations, note that (1
) is going to have the data type int
.
uint32_t inc(uint16_t x) {
uint16_t y = x + 1;
return y;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With