4

I am try to bitwise operate in C. Here is my code:

int main() {
    char c = 127;
    c <<= 1;
    if (c == 0xfe) {
        printf("yes");
    }
    else {
        printf("No");
    }
    return 0;
}

System console print No. What I expect to receive is Yes. the value in c after bit moving is ffffffffe. It seems that system has changed 8bits to a 32bits. Can anyone help me.

user2736738
  • 30,591
  • 5
  • 42
  • 56
Akrios
  • 1,637
  • 2
  • 10
  • 12
  • 1
    You should almost always use unsigned types when doing bitwise operations. – Barmar Mar 01 '18 at 18:27
  • What is mechanism behind bitwise operation. What is the difference. Can you refer me so some paper relating to this. – Akrios Mar 01 '18 at 18:53
  • https://stackoverflow.com/questions/4009885/arithmetic-bit-shift-on-a-signed-integer – Barmar Mar 01 '18 at 18:58

1 Answers1

7

You have correctly figured out the content of the lower byte, i.e. 0xfe. However, there is more to what's actually happening here: when you write

if (c == 0xfe) {
    ...
}

you are comparing c, a char, to an int constant 0xfe. In this situation C rules require promoting char c to int for comparison. Since char is signed on your platform, 0xfe gets promoted to 0xfffffffe, which is why the comparison subsequently fails.

If you want to do the comparison in char type, cast 0xfe to char, like this:

if (c == (char)0xfe) {
    ...
}

Demo 1.

Unsigned characters, on the other hand, would give you no trouble with int promotion, because they fit nicely in an int:

unsigned char c = 127;
c<<=1;
if (c == 0xfe) { // No casting is necessary
    ...
}

Demo 2.

Note: The behavior of c <<= 1 is implementation-defined due to char overflow.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 2
    Note the behavior in `c <<= 1;` is implementation defined, due to the overflow. – Eric Postpischil Mar 01 '18 at 18:36
  • Thank you for the answer, but I was really trying to figure out what is value in c after bit moving. When I printf value in c it shows 0xffff fffe. – Akrios Mar 01 '18 at 18:37
  • @EricPostpischil That's true, an so is the behavior of sign-extending the value. Thanks for the comment! – Sergey Kalinichenko Mar 01 '18 at 18:37
  • `c = 0xfffffffe` after bit moving. it is promoted to 64 bits. Is there a way that doing bit moving would not promote type? – Akrios Mar 01 '18 at 18:40
  • @Akrios The value of `c` is `0xfe`, the remaining `f`s are added by integer promotion in the call to `printf`. In other words, when you print `printf("%x", c)` you are printing `(int)c`, not simply `c`, because C standard does the conversion as part of the call to a vararg function. – Sergey Kalinichenko Mar 01 '18 at 18:40
  • @dasblinkenlight Correct me if I am wrong. Essentially, the value in `c` still is `0xfe` but it is promoted by calling `printf()` function. · – Akrios Mar 01 '18 at 18:44
  • @Akrios `0xfffffffe` is only 32 bits (8 nibbles of 4 bit each). It's not the move that promotes to `int`, it's other operations that do it: printing, comparisons, etc. C does this a lot, so you need to be careful when you work with signed characters. Unsigned characters, on the other hand, would give you no trouble at all Please see the edit. – Sergey Kalinichenko Mar 01 '18 at 18:45
  • @Akrios Yes, that's exactly right. `c` is `0xfe`, but the call to `printf` promotes it to `int`, performing sign extension as part of the process. – Sergey Kalinichenko Mar 01 '18 at 18:46
  • @dasblinkenlight That is so great. unsigned solves problem. – Akrios Mar 01 '18 at 18:47
  • @dasblinkenlight I guess not only `printf()` promotes my c but also doing `==` also promote c to `int` right? – Akrios Mar 01 '18 at 19:24
  • @Akrios Yes, that's right, any comparison operation with `int` would promote `char` to `int`. Same goes with arithmetic operators - if you try `int x = ...; int y = c + x` the value of `c` would be promoted to `int` for the addition. – Sergey Kalinichenko Mar 01 '18 at 19:33