5

After reading the 32 bit unsigned multiply on 64 bit causing undefined behavior? question here on StackOverflow, I began to ponder whether typical arithmetic operations on small unsigned types could lead to undefined behavior according to the C99 standard.

For example, take the following code:

#include <limits.h>

...

unsigned char x = UCHAR_MAX;
unsigned char y = x + 1;

The x variable is initialized to the maximum magnitude for the unsigned char data type. The next line is the issue: the value x + 1 is greater than UCHAR_MAX and cannot be stored in the unsigned char variable y.

I believe the following is what actually occurs.

  • The variable x is first promoted to data type int (section 6.3.1.1/2), then x + 1 is evaluated as data type int.

Suppose there is an implementation where INT_MAX and UCHAR_MAX are the same -- x + 1 would result in a signed integer overflow. Does this mean that incrementing the variable x, despite being an unsigned integer type, can lead to undefined behavior due to a possible signed integer overflow?

Community
  • 1
  • 1
Vilhelm Gray
  • 11,516
  • 10
  • 61
  • 114
  • If `sizeof(unsigned char) == sizeof(int)`, the first scenario applies. – chux - Reinstate Monica Nov 18 '14 at 21:51
  • 1
    @chux Why would a promotion not occur if an `int` can represent the value? – Vilhelm Gray Nov 18 '14 at 21:53
  • I'll review "6.3.1.8 Usual arithmetic conversions" This seems to first apply "Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type." That comes before the "Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type ..." rule. – chux - Reinstate Monica Nov 18 '14 at 21:55
  • @chux I think that section of the paragraph applies only after the typical integer promotions occur for each operand: **6.3.1.8/1** "Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands." – Vilhelm Gray Nov 18 '14 at 22:03
  • 1
    I sit corrected. If `INT_MAX >= UCHAR_MAX`, `unsigned char x` is converted per "Usual arithmetic conversions" to `int`. – chux - Reinstate Monica Nov 18 '14 at 22:17
  • 1
    Suppose this is why code should use `unsigned char y = x + 1u`. – chux - Reinstate Monica Nov 18 '14 at 22:25
  • `INT_MAX == UCHAR_MAX` implies at least 7 padding bits for `int`, that doesn't sound likely to exist. – mafso Nov 18 '14 at 22:32

1 Answers1

5

By my reading of the standard, an implementation which used a 15-bit char could legally store int as a 15-bit magnitude and use a second 15-bit word to store the sign along with 14 bits of padding; in that case, an unsigned char would hold values 0 to 32,767 and an int would hold values from -32,767 to +32,767. Adding 1 to (unsigned char)32767 would indeed be undefined behavior. A similar situation could arise with any larger char size if 32,767 was replaced with UCHAR_MAX.

Such a situation is unlikely, however, compared with the real-world problems associated with unsigned integer multiplication alluded to in the other post.

supercat
  • 77,689
  • 9
  • 166
  • 211