3

Have a look at the example:

unsigned char c = 64; /* 0100 0000 */
c = (c << 2 && 512); /* 512: 10 0000 0000  */

If I shift c two times to the left, I should get from 0100 0000 (64) to this 0001 0000 0000 (256). So my 8-bit char c has only zeroes. At the end, I am wondering why the expression (c << 2 && 512) is true (1) and not false (0), because my c has only zeroes.

B0r1
  • 400
  • 3
  • 15
  • 9
    `c << 2` is `true`. `512` is `true`. `true && true` is `true`. Did you mean to use a bitwise `&` instead? – Eugene Sh. Jan 13 '22 at 18:14
  • 2
    Did you mean to use [bitwise AND](https://en.cppreference.com/w/cpp/language/operator_arithmetic) (`&`) instead of [logical AND](https://en.cppreference.com/w/cpp/language/operator_logical) (`&&`)? – Brian61354270 Jan 13 '22 at 18:15
  • 1
    You need to explain what puzzles you. You seem to intentionally use the logical AND. But I think you expect `c << 2` to be an 8bit 0. Is that your thinking? – Yunnosch Jan 13 '22 at 18:19
  • @Yunnosch Exactly! After shifting the variable c will become 0. But it isn't the same if I assign c = 0, because this will throw false (0). If the reason is the promotion from char to int, it would explain why this become true. – B0r1 Jan 13 '22 at 19:12
  • "After shifting the variable c will become 0." No, it will become the result of `(c << 2 && 512)`. Which is not 0. And `c << 2` is not 0 either. See the answers who provide explanation and visualisation. – Yunnosch Jan 13 '22 at 19:15
  • I meant that. Sorry for misunderstanding. – B0r1 Jan 13 '22 at 19:18
  • @EricPostpischil Which typo do you see? This is not about `&` != `&&`. – Yunnosch Jan 13 '22 at 19:25
  • @user3840170 Which typo do you see? This is not about `&` != `&&`. – Yunnosch Jan 13 '22 at 19:25
  • @4386427 Which typo do you see? This is not about `&` != `&&`. – Yunnosch Jan 13 '22 at 19:25
  • @Yunnosch: It appeared that way because the question explicitly states that shifting yields 1|0000 0000, which is correct, thus making it appear OP knew the shift would produce a non-zero result (256) and was confused why ANDing that with 512 yields a non-zero result. As written, the question still appears that way. It would need to be edited. – Eric Postpischil Jan 13 '22 at 19:34
  • @EricPostpischil Hmm I read exactly that part as an expectation that the 1 is beyond the limit of 8bit datatype, indicated by being beyond the "|". Seeing the selection of the accepted answer it seems to be confirmed to me. And explicit confirmation in the comment answering my question/speculation. I also wish the question would be edited to be clear about that.... – Yunnosch Jan 13 '22 at 19:36
  • B0r1. Please [edit] to clarify the misconception of those who closevoted. At least I think they had one. You could also clarify to confirm them.... – Yunnosch Jan 13 '22 at 19:38
  • I edited my question. The promotion from char to int for variable c in the answers helped me. Then it makes sense – B0r1 Jan 14 '22 at 03:40
  • @Yunnosch What make you think I see a typo? The close reason? Remember that the system shows **only one** close reason but the voters may have used different close reasons... – Support Ukraine Jan 14 '22 at 05:03

3 Answers3

3

From the C Standard (6.5.7 Bitwise shift operators)

3 The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand.

So in this expression

c << 2

the object c is promoted to the type int and the result also has the type int.

As the both operands of the logical AND operator are not equal to 0 then the whole expression evaluates to 1.

From the C Standard (6.5.13 Logical AND operator)

3 The && operator shall yield 1 if both of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.

It seems you are confusing the logical operator AND && with the bitwise operator AND &.

If you will write

c = (c << 2 & 512);

then the variable c will have the value 0.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thanks. The promotion explains everything. Then it makes sense! I really meant the logical AND and not the bit-wise AND. – B0r1 Jan 13 '22 at 19:15
2

& is a bitwise AND. Each bit in its results is the AND of the two corresponding bits in its input. The bitwise AND of 01 0000 00002 and 10 0000 00002 would be 00 0000 00002.

&& is a logical AND. Its result is 1 if both of its operands are non-zero and 0 otherwise. The logical AND of 01 0000 00002 and 10 0000 00002 is 1.

Eugene Sh.
  • 17,802
  • 8
  • 40
  • 61
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • I thought it would only look the 8-bit char. After Vlad explanation about promotion, everything makes sense now. – B0r1 Jan 13 '22 at 19:17
2

The answer by Vlad is the explanation.
Here is a visualisation of how hard it is to get something into a special data type, in the presence of promotion:

#include <stdio.h>

int main()
{
    printf("Hello, World!\n");
    
    unsigned char c = 64;
    
    if (c <<   2 ) {printf("Yes 1.\n");}
    if (c << '\2') {printf("Yes 2.\n");}
    if ((unsigned char)(c << 2)) {printf("Yes 3.\n");} else {printf(" No 3.\n");}
    if ((unsigned char)(c) << (unsigned char)(2)) {printf("Yes 4.\n");} else {printf(" No 4.\n");}
    

    return 0;
}

Output (e.g. here https://www.tutorialspoint.com/compile_c_online.php ):

Hello, World!
Yes 1.
Yes 2.
 No 3.
Yes 4.

The version from your code fails in 1.
A version attempting to use unsigned char operands fails in 2.
Only 3, an explicit cast after the operation manages to override the promotion.
While 4, attempting to use explicit cast on the operands before the operation fails again.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54