5

I am finding the maximum value of a char by simple addition and testing for when the number goes negative:

#include<stdio.h>

/*find max value of char by adding*/
int main(){
  char c = 1;

  while(c + 1 > 0)
    ++c;

  printf("Max c = %d\n",(int)c);  /*outputs Max c = -128*/
  return 0;
}

The while loop tests ahead, so the first time c+1 is negative it breaks and we print the value of c. However, the programming is outputting the negative number!

Why doesn't this program output 127?

bgoldst
  • 34,190
  • 6
  • 38
  • 64
user1717828
  • 7,122
  • 8
  • 34
  • 59
  • I would use limits.h for this. But if you insist, use int as counter and compare it with counter casted as char `c != (char) c` – KIIV Jul 25 '16 at 19:58

2 Answers2

5

There is an implicit cast occurring in the while conditional which is causing the comparison to work on ints rather than chars.

If you change it to

while((char)(c + 1) > 0)
    ++c;

then it will print 127.

bgoldst
  • 34,190
  • 6
  • 38
  • 64
  • 4
    Correct... except I think the correct terminology would be "integer promotion", not "implicit cast"...? – phonetagger Jul 25 '16 at 20:01
  • 1
    @phonetagger Thanks for the comment. My understanding is that integer promotion is a specific case of implicit casting, thus both terms are technically correct. – bgoldst Jul 25 '16 at 20:10
  • 1
    "Integer promotion" is searchable, in case anyone wants to find out more about it – anatolyg Jul 25 '16 at 20:19
  • 1
    There is no such thing as an "implicit cast". A cast is an explicit conversion; a cast operator consists of a type name in parentheses. A conversion not using a cast is an *implicit conversion*. – Keith Thompson Jul 25 '16 at 20:51
0

Signed integer overflow is undefined behavior. This means that a conforming C compiler is allowed to change c + 1 > 0 to true, because the addition "cannot" overflow.

This means that your program could legitimately be compiled to an endless loop.

Danilo Piazzalunga
  • 7,590
  • 5
  • 49
  • 75
  • While this may be true, it doesn't explain the behavior the OP observed. – phonetagger Jul 25 '16 at 20:13
  • This is only undefined if `INT_MAX == CHAR_MAX`. – EOF Jul 25 '16 at 20:23
  • 1
    @EOF - I'm not sure that's right. The right-hand side of the expression `c + 1` is of type `int` and its left-hand-side is a smaller type, so the entire result of that expression is an `int`. So the comparison `c + 1 > 0` is one `int` compared to zero (another `int`, but a special one). – phonetagger Jul 25 '16 at 20:33
  • @phonetagger: I'm not sure where you're going with that. The expression `(c+1<0)` is undefined if `c+1` is evaluated at `int`-precision, and `c` is `INT_MAX`. If `c` is of type char, and `char` is equivalent to `signed char`, and `INT_MAX == CHAR_MAX`, this can indeed happen. If `CHAR_MAX < INT_MAX`, it cannot. – EOF Jul 25 '16 at 20:37
  • @EOF @phonetagger Either way, the `++c;` in the loop body is still undefined (or maybe implementation defined) if `char` is signed and `c` is `CHAR_MAX`. – Dmitri Jul 25 '16 at 21:16
  • @EOF - I don't see how `CHAR_MAX < INT_MAX` or `CHAR_MAX == INT_MAX` has anything to do with it. Regardless of the type of `c`, by the time this code adds `1` to it, it's already been promoted to an `int`. So an optimizer might see the expression `c + 1`, and knowing that `c` had an initial value of `1` and the only reassignment to it is to increment it, surmise that the result of `c + 1` will necessarily be greater than zero (since signed integer overflow is undefined). So I don't see how the relationship between `INT_MAX` and `CHAR_MAX` has anything to do with it. – phonetagger Jul 25 '16 at 22:02
  • @phonetagger If `CHAR_MAX < INT_MAX`, then there is no overflow in `(c+1>0)` and the compiler could only assume it's always true if it can assume `c` will never become negative -- and *that* assumption would rely on either `char` being unsigned, or the undefined behaviour of the `++c;` overflow *in the loop body*, rather than in the `(c+1>0)` expression. – Dmitri Jul 25 '16 at 22:59
  • @Dmitri: `c++` is no more undefined than `c + 1`. – EOF Jul 25 '16 at 23:08
  • @EOF implementation defined, then... `c = c + 1` when `c` is `CHAR_MAX` would assign a value too large for `char` to a `char`, which is implementation defined (for signed `char`, at least). – Dmitri Jul 25 '16 at 23:15
  • @Dmitri: Yes, implementation-defined indeed. So? Your original claim was that `c++` was *undefined*, which is clearly wrong. If `char` is equivalent to `signed char`, and `INT_MAX > CHAR_MAX`, the code not undefined, contrary to this answer. Of course, if `char` is equivalent to `unsigned char`, the behavior is undefined regardless of `CHAR_MAX`, but for an entirely different reason. – EOF Jul 25 '16 at 23:18
  • @EOF What I was getting at is that you were right that `c+1>0` is only undefined behaviour if `INT_MAX == CHAR_MAX`. However, because of the `++c;` expression in the loop a hypothetical implementation could still assume it's always true as long as on that implementation `++c;` won't go negative (which is allowed, even with signed `char`). Obviously the OP's implementation doesn't work that way, though... – Dmitri Jul 25 '16 at 23:34
  • My point is that this answer is dead wrong for all but the most esoteric implementations. It remains wrong even for the odd implementation that doesn't modulo reduce on narrowing signed integer conversion, because even then the origin of the undefined behavior *isn't* the conversion itself, but the infinite loop with non constant-expression controlling expression. – EOF Jul 25 '16 at 23:44