-1

I have the following code:

char x = -1;
int y = x;

printf("%u\n", x);
printf("%u\n", y);

The output is:

4294967295
4294967295

I dont understand why x can get such a value. I know that the maximum value of a unsigned char is 255 and for a signed char 127. How can it be 4294967295?

DanielC
  • 13
  • 1
  • 6
  • 1
    Assuming that `char` is signed on your platform, then this is *undefined behaviour* - you're passing a signed value to `printf`, but telling it to expect (via `%u`) an unsigned value. – Oliver Charlesworth Dec 01 '17 at 18:11
  • It is undefined behavior b/c you are using the incorrect format specificer but also [variadic function promote their arguments to wider types as well](https://stackoverflow.com/a/28097654/1708801) ... `bool, char, short, and unscoped enumerations are converted to int or wider integer types as in integer promotion` – Shafik Yaghmour Dec 01 '17 at 18:12
  • C != C++. Tag only with the language that you're using, unless both are actually relevant. – tambre Dec 01 '17 at 18:13
  • 1
    FWIW, the same output could also occur on rare (unicorn?) platforms with with `char` as a 32-bit `unsigned char` and 32-bit `int/unsigned`. In that case `printf("%u\n", x);` is well defined and output `"4294967295\n"` is expected. – chux - Reinstate Monica Dec 01 '17 at 18:41

4 Answers4

2

For functions like printf that use variadic arguments, any integral types smaller than an int (char and short) are implicitly promoted to int. The same is true with floating-point numbers, float is promoted to double.

Hence, your char is being sign-extended to an int with value -1, and since you are printing it as unsigned, in 2's complement you get UINT_MAX.

Edit: as chux notes below, if your char defaulted to unsigned (this depends on your compiler/platform), the answer would be 255 instead. When promotion occurs, the value will be zero-extended instead of sign-extended.

Andrew Sun
  • 4,101
  • 6
  • 36
  • 53
  • @EricPostpischil Yep, just fixed that. Thanks! – Andrew Sun Dec 01 '17 at 18:20
  • 3
    As others have noted, although two’s complement explains why OP got this particular result, the behavior is actually undefined. – Eric Postpischil Dec 01 '17 at 18:23
  • 1
    Although "char is being sign-extended to an int with value -1" may apply in this case, `char` may be unsigned and output could be `"255\n"`. – chux - Reinstate Monica Dec 01 '17 at 18:31
  • "any integral types smaller than an int" ? if input is unsigned char than also it should promoted to int ? It's not. – Achal Dec 01 '17 at 18:57
  • @achal: C 2011 [N1570] 6.3.1.1 2: “If an **int** can represent all values of the original type (…), the value is converted to an **int**; otherwise it is converted to an **unsigned int**.” In most C implementations `unsigned char` is narrower than `int`, although [not always](https://stackoverflow.com/questions/17882326/is-unsigned-char-always-promoted-to-int). – Eric Postpischil Dec 01 '17 at 19:47
0

The variable has the -1 value. but you specified that %u(unsigned int) in the printf

int is 32bit so 2^32 = 4294967296 => -1 + 4294967296 =4294967295 hope you understand this.

Lead Developer
  • 1,146
  • 10
  • 26
0

You're misusing a format specifier and invoking undefined behavior because of that.My understanding is that in each case, the number of converted to its two's compliment binary representation which is same for -1 or 4294967295. That is why %u for signed prints 4294967295 by ignoring -ve leftmost bit. When used %d for signed int, it uses left most bit as -ve flag and prints -1. Similarly %u for unsigned prints unsigned value but %d causes it to treat the number as signed and thus prints -1

-1

If your input qualifier is signed, be careful of sign bit, if sign bit is 1, you will get negative value. Though x is signed char, you are expecting 1 byte value but you are getting 4 byte value because of sign bit copy mechanism.

x value :

x =  -1 = 0000 0000 0000 0000 0000 0000 1111  1111
                                        |
                                        sign bit, this bit get's copied into remaining bytes, so it becomes like

        = 1111 1111 1111 1111 1111 11111 1111 1111 => calculates this => 4294967295 
        = |
         sign bit , now you are printing  in %u format i.e unsigned so it will ignore signed bit and you are getting big value.

Same if you are printing in %d or %i format

printf("%d\n", x); // it prints -1 bcz %d will check sign bit which is 1 i.e it will prints -ve value, so it's prints -1 

I just tried to explains why you are getting such output but It's undefined behaviour as mentioned in some comments if you are not using correct format specifier. you can refer different C standard.

EDIT : to justify my point(linux machine) let's consider below code

int main()
{
        unsigned char x = -1;
        printf("%u\n",x);
        /*In above printf input is unsigned, so compiler won't 
         check sign bit, even though sign bit is 1, result 
        will be +ve only. */

        printf("%d\n",x);//some of you may expects -1 because of %d, it's wrong.
       /* In above printf it's printing 255 not because of format 
        specifier, it's because of your input qualifier(which is 
        unsigned in this case) */

        return 0;
}
Achal
  • 11,821
  • 2
  • 15
  • 37