0

I have had a long discussion with a group of colleagues regarding the correct answer of the question in the following code section. I have relied on a couple of discussions here on stackoverflow.com about overflow in signed integers for my answer. So, I told them that the choices should contain "undefined behavior" and it should be the correct answer. But they said the answer should be (C) and they provided some links of the same question on many sites providing the same question and answer. I will quote the question, its answer and explanation as given in the links they provided. So, what should be the correct answer? Thanks

  1. What will be output if you will compile and execute the following c code?
#include<stdio.h>
int main() {
    char c=125;
    c=c+10;
    printf("%d",c);
    return 0;
}

Choices:

(A) 135
(B) +INF
(C) -121
(D) -8
(E) Compiler error

Explanation:

As we know char data type shows cyclic properties i.e. if you will increase 
or decrease the char variables beyond its maximum or minimum value 
respectively it will repeat same value according to following cyclic     
order:
So,
125+1= 126
125+2= 127
125+3=-128
125+4=-127
125+5=-126
125+6=-125
125+7=-124
125+8=-123
125+9=-122
125+10=-121
Answer: (C)
a3f
  • 8,517
  • 1
  • 41
  • 46
  • 4
    The person writing the question seems to have forgotten that `char` can be both `signed` *and* `unsigned`, it's an implementation detail. – Some programmer dude Mar 25 '18 at 10:51
  • 3
    If `char` is `signed`, then the behaviour is implementation-defined (which you should probably treat the same as *undefined* for most practical purposes). – Oliver Charlesworth Mar 25 '18 at 10:52
  • Maybe this will help: https://stackoverflow.com/questions/75191/what-is-an-unsigned-char - it's unclear whether `char` is signed or not, so this indeed may be undefined (I think). – kabanus Mar 25 '18 at 10:52
  • make it A or C depending on the implementations. – Jean-François Fabre Mar 25 '18 at 11:00
  • So both A: 135 (char is unsigned) and C: -121 (char is signed) are correct. To tease your teacher you should answer A, and if he disaproves of your answer, give him a lengthy lecture that signedness of char is implementation defined :) – Paul Ogilvie Mar 25 '18 at 11:00
  • Guys, supposing char is signed.. What should be the answer? "Signed char" in C is an integer type, right? And overflow in integer types is undefined behavior. So, the answer should be "undefined behavior", right? – Alsayed Alsisi Mar 25 '18 at 11:10

1 Answers1

6

Depends on the system. It is implementation defined whether char is signed, and whether 135 is a representable value of a signed char type.

If char is an unsigned type or if CHAR_BIT is greater than 8, then the correct output will be (A) 135 since that is a representable value.

If char is a signed type and CHAR_BIT is 8, then none of the answers is correct (in the context of C language): The value will be implementation defined or an implementation defined signal is raised. Although, a typical implementation defined value that you get on CPU's that use two's complement (which is most CPU's) will be -121. This is however not guaranteed by the language.

To sum up discussion in the comments on why this is not UB: There are no operations on integers smaller than int. Operands that are smaller integers are promoted to int. 125 + 10 does not overflow with int, the result is 135. The 135 value is assigned to a char object. This is not overflow, and behaviour is not undefined. If 135 is not representable by char, then the value will be implementation defined (C11 §6.3.1.3/3).

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • If it's signed, then the behaviour is implementation-defined. – Oliver Charlesworth Mar 25 '18 at 11:15
  • @OliverCharlesworth is signed integer overflow implementation defined in C (I wrote the answer back when this was tagged with C++)? – eerorika Mar 25 '18 at 11:17
  • Great this is what I have said. Could you please provide some references that I can make use of in the discussion with my colleagues? – Alsayed Alsisi Mar 25 '18 at 11:19
  • 1
    I think the key is that it's not overflow in this case. As an operand to `+`, the `char` is first promoted to `int`, so the `+` evaluates to `135`. The conversion back to `char` then falls foul of 6.3.1.3 in the spec - it's out of the representable range. – Oliver Charlesworth Mar 25 '18 at 11:20
  • @Oliver, I would love too to have an answer to user2079303 question in the comments. – Alsayed Alsisi Mar 25 '18 at 11:21
  • @OliverCharlesworth wow, I hand't thought of that. So, `short` and `char` additions never have UB assuming they're smaller than `int`? – eerorika Mar 25 '18 at 11:21
  • For reference, I think @OliverCharlesworth references C11 §6.3.1.3¶3, which I think would apply here (`Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.`). – a3f Mar 25 '18 at 11:24
  • Guys, I still don't get it. Now, if the char variable promoted to int and the expression that evaluates to 135 is computed and the answer then stored back in the char variable, now 135 is outside the range that a signed char can store. Wouldn't this be overflow? And signed integer types overflow is undefined in C, right? – Alsayed Alsisi Mar 25 '18 at 11:29
  • With `CHAR_BIT==8 && CHAR_MAX == SCHAR_MAX`, would it still be correct to call `c=c+10;` an overflow (with implementation-defined outcome) or is a signed overflow always undefined? – a3f Mar 25 '18 at 12:48
  • 1
    @a3f there is **no** overflow in arithmetic happening here, because the arguments are promoted to `int` that will have the range up to at least +32767. The behaviour of signed overflow is *undefined* **wherever it happens**. The program is not strictly conforming i.e. not maximally portable, whether or not a signal is raised, so YMMV. – Antti Haapala -- Слава Україні Mar 25 '18 at 12:51
  • 1
    @AlsayedAlsisi *"Wouldn't this be overflow?"*, no that wouldn't be that which is called overflow in C. It would be a ~conversion where the value is not representable in the resulting type. – Antti Haapala -- Слава Україні Mar 25 '18 at 12:54
  • @AnttiHaapala I meant the cast back from `int` on the RHS to `char`. Your second comment clears that up. Thanks! – a3f Mar 25 '18 at 12:55
  • @a3f there is no *cast*, there is only *conversion*. The word **cast** means the `(type)value` construct i.e. an **explicit conversion** or removal or addition of type qualifiers... - it isn't present here. – Antti Haapala -- Слава Україні Mar 25 '18 at 14:11