Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unsigned Overflow in C

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.

like image 358
Luís Fernando Schultz Xavier Avatar asked Feb 26 '23 02:02

Luís Fernando Schultz Xavier


2 Answers

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.

like image 99
R.. GitHub STOP HELPING ICE Avatar answered Mar 07 '23 07:03

R.. GitHub STOP HELPING ICE


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;
}
like image 28
Steve-o Avatar answered Mar 07 '23 05:03

Steve-o