6

Let's say I have a variable i that comes from external sources:

int i = get_i();

Assuming i is INT_MIN and two's complement representation, is -i undefined?

SoniEx2
  • 1,864
  • 3
  • 27
  • 40

3 Answers3

14

It depends on the platform. C supports three representations for negative numbers (see section 6.2.6.2 of the C99 standard):

  • Two's complement.
  • One's complement.
  • Sign and magnitude.

With one's complement and sign and magnitude, -INT_MIN is defined (and equal to INT_MAX). With two's complement, it depends on whether the value with sign bit 1 and all value bits zero is a trap representation or a normal value. If it's a normal value, -INT_MIN overflows, resulting in undefined behavior (see section 6.5 of the C99 standard). If it's a trap representation, -INT_MIN equals INT_MAX.

That said, most modern platforms use two's complement without trap representations, so -INT_MIN typically results in undefined behavior.

nwellnhof
  • 32,319
  • 7
  • 89
  • 113
  • The last paragraph seems unclear to me, I think you are trying to say that if `INT_MIN == -INT_MAX` then `-INT_MIN == INT_MAX`, otherwise `-INT_MIN` is undefined behaviour – M.M May 18 '16 at 21:02
  • @M.M What I'm trying to say is under which conditions exactly `INT_MIN == -INT_MAX` and that this condition can even be true on a two's complement platform (at least theoretically). – nwellnhof May 19 '16 at 00:35
  • I spent a while looking in the wrong parts of sections 6.2.6.2 and 6.5 searching for the statement that `-INT_MIN` is undefined behavior. I did eventually find it (I think), in item 6.5-5, which says "If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined." – pnkfelix Sep 28 '16 at 21:17
  • 1
    @pnkfelix that only matters if `-INT_MIN` falls outside the range of values an integer can represent. If you're using sign-magnitude or ones-complement, `-INT_MIN` is within the range of values an integer can represent, so `-INT_MIN` is perfectly fine. Of course, it's undefined behaviour if it overflows, as it would with twos-complement. – CoffeeTableEspresso Apr 11 '19 at 22:18
5

Platforms may choose to define the behavior, but the C Standard does not require that they guarantee anything about it. While historically microcomputer compilers have relatively consistently behaved as though -INT_MIN would yield INT_MIN or in some cases a number that behaves like a value one larger than INT_MAX, it has become more fashionable to instead have it retroactively change the value of whatever was being negated. Thus, given:

int wowzers(int x)
{
  if (x != INT_MIN) printf("Not int min!");
  return -x;
}

a hyper-modern compiler may use the expression -x to determine that x can't have been equal to INT_MIN when the previous comparison was performed, and may thus perform the printf unconditionally.

Incidentally, gcc 8.2 will use the UB-ness of negating INT_MIN to "optimize" the following

int qq,rr;
void test(unsigned short q)
{
    for (int i=0; i<=q; i++)
    {
        qq=-2147483647-i;
        rr=qq;
        rr=-rr;
    }
}

into code that unconditionally stores -2147483647 to qq and 2147483647 to rr. Removing the rr=-rr line will make the code store -2147483647 or -2147483648 into both qq and rr, depending upon whether q is zero.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • Do you have supporting evidence for the hypothesis for hyper-modern compilers? – Yatharth Agarwal Jan 28 '18 at 16:11
  • @YatharthAgarwal: I have identified situations where evaluation of an expressions that would cause overflow with certain argument values will cause compilers to infer that such arguments will not be received. I haven't identified cases in today's compilers where negation of INT_MIN in particular would cause that, but the authors of compilers like gcc make very clear that they make no promises about future behavior in cases not mandated by the Standard and aren't explicitly documented. – supercat Jan 28 '18 at 23:23
  • 1
    @YatharthAgarwal: I added an example of a function where attempting to negate a value equal to `INT_MIN` in gcc 8.2 will affect the stored value of another object. – supercat Dec 07 '18 at 21:55
  • Woah—nice example! – Yatharth Agarwal Dec 08 '18 at 09:27
  • @YatharthAgarwal: Even more interesting is the compiler's behavior if `q` is changed to `-2147483646-i`. The generated code ends up being less efficient than if the `rr=-rr` line were replaced with `rr=-(unsigned)rr`, so the compiler's treatment of UB doesn't even improve code efficiency. – supercat Dec 09 '18 at 21:15
2

Is negating INT_MIN undefined behaviour?

Yes, when INT_MIN < -INT_MAX - which is very common (2's complement). It is integer overflow.

int i = get_i();

#if INT_MIN < -INT_MAX
if (i == INT_MIN) {
  fprintf(stderr, "Houston, we have a problem\n");
  // Maybe return or exit here.
}
#endif 

int j = -i;

Houston, we have a problem

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256