0

Why are these two versions of code different? I had been under the impression that unsigned integer overflow is well-defined in C and that if you have uint16_t a,b then a-b has a result type of uint16_t.

#include <stdint.h>

uint32_t frobnicate1(uint32_t prevsum, uint16_t command, uint16_t response)
{
    uint32_t error = command-response;
    return prevsum + error; 
}

uint32_t zoop1()
{
    return frobnicate1(0, 30001, 30002);
}

uint32_t frobnicate2(uint32_t prevsum, uint16_t command, uint16_t response)
{
    uint16_t error = command-response;
    return prevsum + error; 
}

uint32_t zoop2()
{
    return frobnicate2(0, 30001, 30002);
}

But zoop1() returns -1 (not expected!!!) whereas zoop2() returns 65535 (expected).

When I see command-response and the result is -1 modulo 65536 = 65535, and is supposed to have type uint16_t, I'm wondering why the compiler is allows to promote 65535 to -1 when going to uint32_t.

(Tried on godbolt.org with x86-64 gcc and clang -O2 -Wall)

Jason S
  • 184,598
  • 164
  • 608
  • 970
  • 1
    Only if `sizeof(unsigned int) == sizeof(uint16_t)`. Otherwise integer promotions occur before the difference is calculated, so the result is `int`. – Jonathan Leffler Oct 30 '22 at 03:00
  • 2
    https://stackoverflow.com/questions/44455248/integer-promotion-in-c – Hans Passant Oct 30 '22 at 03:00
  • @HansPassant related but different question. – Jason S Oct 30 '22 at 03:55
  • I'm willing to accept a dupehammer verdict but not with that redirection. The best original to cite is https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules – Jason S Oct 30 '22 at 04:21

1 Answers1

3

Not necessarily.

C has no arithmetic operations on integer types narrower than int and unsigned int. If uint16_t is narrower than unsigned int (as it is in most implementations), then any operands of type uint16_t are promoted to int before an operation is applied.

uint16_t is likely to be defined as unsigned short; the same thing happens with operands of type unsigned short, which are typically promoted to int.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • "C has no arithmetic operations on integer types narrower " -- what? where is that in the standard? I'm looking at N1256 https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf -- currently looking at 6.3.1.8 usual arithmetic conversions – Jason S Oct 30 '22 at 03:58
  • "Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands: If both operands have the same type, then no further conversion is needed" – Jason S Oct 30 '22 at 04:00
  • sigh, it's clarified in a footnote: "EXAMPLE 2 In executing the fragment char c1, c2; /* ... */ c1 = c1 + c2; the ‘‘integer promotions’’ require that the abstract machine promote the value of each variable to int size and then add the two ints and truncate the sum. Provided the addition of two chars can be done without overflow, or with overflow wrapping silently to produce the correct result, the actual execution need only produce the same result, possibly omitting the promotions." – Jason S Oct 30 '22 at 04:31