1

I am fairly certain that subtracting one uint8_t from another should result in another unsigned number, but some of my results are confusing me.

  uint8_t a = 2;
  uint8_t b = 1;
  uint8_t c = -a;
  long d = b - a;
  long e = b + c;

When I obtain the value of d it produces -1, while e is as I would expect 255. This is a bug with the version of gcc I am using.....right?

For reference I am using the arm-none-eabi-g++ compiler for my MSP-432.

Looking at this seems to indicate that gcc just seems to make the same mistake here.

Looking at this SO question it seems that godbolt and the arm gcc is wrong.

What is going on here?

Community
  • 1
  • 1
DarthRubik
  • 3,927
  • 1
  • 18
  • 54

2 Answers2

6

This is a bug with the version of gcc I am using.....right?

No, it's not. Something that simple being buggy in a big compiler like gcc is highly unlikely.

What happens is due to the "usual arithmetic conversions", specifically "integer promotion":

The unary - promotes a to int, then the (int)-2 gets converted back to uint8_t in the assignment, yielding c == 254 (which is the representative of the equivalence class of -2 in Z mod 2^8 that lies in [0, 2^8)).

Likewise, the binary + and - in the lines below that promote to int, so we end up with

d == (int)b - (int)a == (int)1 - (int)2 == -1

and

e == (int)b + (int)c == (int)1 + (int)254 == 255

So everything is working fine as mandated by the standard.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
2

The reason is that binary operators undergo integral promotion before doing the work, and since int can hold all possible values from uint8_t, that choice is used (see http://en.cppreference.com/w/cpp/language/implicit_conversion#Integral_promotion). Thus the subtraction is done as a signed operation.

When calculating e the act of storing a value in c already resulted in your expected modulo math, storing 254 which is then added to b's value of 1.

Mark B
  • 95,107
  • 10
  • 109
  • 188