Is INT_MAX + (-1) an undefined behavior?

2

In C++ an overflow of signed types is undefined behavior. Is the following example an undefined behavior as well?

#include <limits.h>

int f() {
  int a = INT_MAX;
  int b = -1;
  return a + b;
}

It is not an overflow in math context, but a CPU will see it probably like add 0x7fffffff 0xffffffff.

c++
undefined-behavior
integer-overflow
asked on Stack Overflow Dec 13, 2017 by Paweł Bylica • edited Dec 13, 2017 by Stargateur

3 Answers

10

The example you give is not an overflow.

From Wikipedia (https://en.wikipedia.org/wiki/Integer_overflow):

... an integer overflow occurs when an arithmetic operation attempts to create a numeric value that is outside of the range that can be represented with a given number of bits – either larger than the maximum or lower than the minimum representable value.

INT_MAX + (-1) is not outside of the range representable by the int type, and the result is defined.

answered on Stack Overflow Dec 13, 2017 by payne
8

Since the result of INT_MAX + (-1) is within the range of representable values of int, it is well defined

You should stop viewing the language as a thin layer over assembly or machine code.

In regards to undefined-ness of a program, there is no CPU, there is only the abstract machine on which the program runs.

answered on Stack Overflow Dec 13, 2017 by Passer By • edited Dec 13, 2017 by Passer By
1

On two's-complement systems, carry and overflow are distinct concepts. Many such systems are designed to support multi-word arithmetic. A carry will be reported if the arithmetic sum, interpreting the values as unsigned, would exceed the range of the type. An overflow will be reported after any computation where the carry into the upper bit differs from the carry out, but will only be meaningful following the computation of the upper byte.

On an 8-bit system, for example, "int" would typically be two bytes, INT_MAX would be 0x7F:0xFF and -1 would be 0xFF:FF. Addition is performed by adding the two lower bytes, and then adding the two upper bytes with a carry from the lower.

  • Adding 0xFF to 0xFF yields 0xFE and carry but no overflow (carry both into and out of the upper bit).

  • Adding 0x7F to 0xFF yields 0x7E with no carry nor overflow (carry neither into nor out of the upper bit).

Such details typically shouldn't matter to a C programmer, since compilers typically provide no way to access the overflow flag, nor any way of ensuring that calculations are performed in a way that would make the flag meaningful at any particular point in the code. Nonetheless, the C89 rationale notes:

C code can be non-portable.
Although it strove to give programmers the opportunity to write truly portable programs, the C89 Committee did not want to force programmers into writing portably, to preclude the use of C as a “high-level assembler”: the ability to write machine- specific code is one of the strengths of C. It is this principle which largely motivates drawing the distinction between strictly conforming program and conforming program (§4).

Note, btw, that the rationale for making small unsigned types promote to signed int strongly implies that authors of the C89 expected that something like the following should be safe on commonplace platforms:

unsigned mul_mod_65536(unsigned short x, unsigned short y)
{ return (x*y) & 0xFFFF; }

Nonetheless, such code may malfunction when processed on commonplace 32-bit platforms when processed by excessively-"clever" optimizing compilers like gcc. There is no reason that machine code generated for such a function should care about whether the value of x*y exceeds INT_MAX, since the upper bits of the result are going to get chopped off and the lower bits would be correct in any case. In some cases, however, if gcc knows e.g. that y will be 65535, it may decide that since x*y "can't" exceed INT_MAX, x "can't" exceed 0x8000. The authors of the Standard may not have wanted to preclude the possibility of C being used as a high-level assembler, but that doesn't meant that compiler writers share such feeling.

answered on Stack Overflow Dec 14, 2017 by supercat

User contributions licensed under CC BY-SA 3.0