8
#include <stdio.h>
int main()
{
    unsigned char i=0x80;
    printf("%d",i<<1);
    return 0;
}

Why does this program print 256?

As I understand this, since 0x80= 0b10000000, and unsigned char has 8 bits, the '1' should overflow after left shift and the output should be 0, not 256.

Variance
  • 873
  • 2
  • 10
  • 10
  • 2
    Don't want to post as an answer because I'm not 100% sure, but isn't it because %d is an integer? So, the code behind the scenes probably assigns `i<<1` to an integer to print it, which means that it fits and doesn't overflow. Try doing `printf("%c", i<<1);`? – Stephen Jul 30 '10 at 16:45
  • @Stephen: Should have posted the answer ;) – KevenK Jul 30 '10 at 16:50
  • @Stephen:The output is blank when I use %c. – Variance Jul 30 '10 at 16:52
  • Oh well, I guess I was sort of on the right track. Sorry %c didn't work - I didn't have a compiler to hand to check it! – Stephen Jul 30 '10 at 16:53
  • On most compilers, `i << n` will produce an integer, regardless of the original type. – Brian S Jul 30 '10 at 16:59

2 Answers2

14

This is a result of C's integer promotion rules. Essentially, most any variable going into an expression is "promoted" so that operations like this do not lose precision. Then, it's passed as an int into printf, according to C's variable arguments rules.

If you'd want what you're looking for, you'd have to cast back to unsigned char:

#include <stdio.h>
int main()
{
    unsigned char i=0x80;
    printf("%d",((unsigned char)(i<<1)));
    return 0;
}

Note: using %c as specified in Stephen's comment won't work because %c expects an integer too.

EDIT: Alternately, you could do this:

#include <stdio.h>
int main()
{
    unsigned char i=0x80;
    unsigned char res = i<<1;
    printf("%d",res);
    return 0;
}

or

#include <stdio.h>
int main()
{
    unsigned char i=0x80;
    printf("%d",(i<<1) & 0xFF);
    return 0;
}
Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • Could you cast `(i<<1)` to `unsigned char`? – nmichaels Jul 30 '10 at 17:11
  • 1
    @Nathon: Isn't that what I did? – Billy ONeal Jul 30 '10 at 17:32
  • 1
    Weird, I must have my blinders turned on. – nmichaels Jul 30 '10 at 18:58
  • 1
    "using %c as specified in Stephen's comment won't work because %c expects an integer too." --> `"%c"` and `"%d"` both accept an `int`. `"%c"` converts its `int` to an `unsigned char` and then prints that character. – chux - Reinstate Monica Oct 14 '15 at 20:45
  • @R..: For _completeness_, it should be mentioned that `unsigned char` promotes to `signed int` **or** `unsigned int` depending on whether or not all the values of `unsigned char` can be represented in a `signed int`, and that the `"%c"` specifier expects a `signed int` which is one of several integer types. – Nisse Engström Oct 14 '15 at 21:04
  • @NisseEngström on what platform are there values of unsigned char that can't be represented as a signed int? – Billy ONeal Oct 16 '15 at 07:31
  • @BillyONeal: I don't know of any myself, but I believe it is allowed by the (-99) C standard. There are some interesting platforms mentioned in [this Usenet thread](https://groups.google.com/forum/m/#!msg/comp.lang.c/kSQi_DRiXpw/aL1GITig9I4J). – Nisse Engström Oct 18 '15 at 21:52
  • @Nisse: I try to avoid hypothetical details about platforms that in all likelihood do not actually exist when answering beginner questions. – Billy ONeal Oct 18 '15 at 21:53
  • @BillyONeal: Some of the systems mentioned are in the DSP 56xxx family. With a little bit of googling, one can find the [DSP56000 Family C Compiler Manual](http://www.google.se/url?q=http://www-mipp.fnal.gov/TPC/DAQ/56KCCUM.pdf&sa=U&ved=0CBMQFjAAahUKEwjiv_iupNnIAhXi33IKHYqCB3c&usg=AFQjCNE14jYzIE6S80MB_jTxJvr7n8x8QA). Section 4.4 says that "**sizeof(char) is equal to sizeof(int)**", and section 4.4.1 lists the maximum values of the integer types: "**unsigned char** ... **0xFFFFFF**" and "**int** ... **8388607**". – Nisse Engström Oct 23 '15 at 19:14
0

Don't forget the format specifically for printing unsigned.

printf("%u",(unsigned char)(i<<1));
Paul E.
  • 259
  • 1
  • 4
  • Due to C's promotion rules, the argument will most likely be passed to `printf` as `signed int`, not `unsigned`. You should cast the argument to a type that matches the format specifier. – Nisse Engström Oct 14 '15 at 19:44