-1

The output comes to be the 32-bit 2's complement of 128 that is 4294967168. How?

#include <stdio.h>
int main()
{
    char a;
    a=128;
    if(a==-128)
    {
        printf("%u\n",a);
    }
    return 0;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278

3 Answers3

4

Compiling your code with warnings turned on gives:

warning: overflow in conversion from 'int' to 'char' changes value from '128' to '-128' [-Woverflow]

which tell you that the assignment a=128; isn't well defined on your plat form.

The standard say:

6.3.1.3 Signed and unsigned integers

1 When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.

2 Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

3 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.

So we can't know what is going on as it depends on your system.

However, if we do some guessing (and note this is just a guess):

128 as 8 bit would be 0b1000.0000

so when you call printf where you get a conversion to int there will be a sign extension like:

 0b1000.0000 ==> 0b1111.1111.1111.1111.1111.1111.1000.0000

which - printed as unsigned represents the number 4294967168

Community
  • 1
  • 1
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • Just to add to this answer, in some architectures this `char a = 128` might produce 0, and not -128. There was an old old question on SO, I cannot find it. –  Jun 26 '18 at 17:24
2

The sequence of steps that got you there is something like this:

  1. You assign 128 to a char.
  2. On your implementation, char is signed char and has a maximum value of 127, so 128 overflows.
  3. Your implementation interprets 128 as 0x80. It uses two’s-complement math, so (int8_t)0x80 represents (int8_t)-128.
  4. For historical reasons (relating to the instruction sets of the DEC PDP minicomputers on which C was originally developed), C promotes signed types shorter than int to int in many contexts, including variadic arguments to functions such as printf(), which aren’t bound to a prototype and still use the old argument-promotion rules of K&R C instead.
  5. On your implementation, int is 32 bits wide and also two’s-complement, so (int)-128 sign-extends to 0xFFFFFF80.
  6. When you make a call like printf("%u", x), the runtime interprets the int argument as an unsigned int.
  7. As an unsigned 32-bit integer, 0xFFFFFF80 represents 4,294,967,168.
  8. The "%u\n" format specifier prints this out without commas (or other separators) followed by a newline.

This is all legal, but so are many other possible results. The code is buggy and not portable.

Make sure you don’t overflow the range of your type! (Or if that’s unavoidable, overflow for unsigned scalars is defined as modular arithmetic, so it’s better-behaved.) The workaround here is to use unsigned char, which has a range from 0 to (at least) 255, instead of char.

Davislor
  • 14,674
  • 2
  • 34
  • 49
0

First of all, as I hope you understand, the code you've posted is full of errors, and you would not want to depend on its output. If you were trying to perform any of these manipulations in a real program, you would want to do so in some other, more well-defined, more portable way.

So I assume you're asking only out of curiosity, and I answer in the same spirit.

Type char on your machine is probably a signed 8-bit quantity. So its range is from -128 to +127. So +128 won't fit.

When you try to jam the value +128 into a signed 8-bit quantity, you probably end up with the value -128 instead. And that seems to be what's happening for you, based on the fact that your if statement is evidently succeeding.

So next we try to take the value -128 and print it as if it was an unsigned int, which on your machine is evidently an 32-bit type. It can hold numbers in the range 0 to 4294967295, which obviously does not include -128. But unsigned integers typically behave pretty nicely modulo their range, so if we add 4294967296 to -128 we get 4294967168, which is precisely the number you saw.

Now that we've worked through this, let's resolve in future not to jam numbers that won't fit into char variables, or to print signed quantities with the %u format specifier.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103