为什么在 C 中用 && 对值和条件进行位移后表达式为真

Why is the expression true after bit shifting the value and condition with && in C

看看这个例子:

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

如果我将 c 向左移动两次,我应该从 0100 0000 (64) 到这个 0001 0000 0000 (256)。所以我的 8 位字符 c 只有零。最后,我想知道为什么表达式 (c << 2 && 512) 为真 (1) 而不是假 (0),因为我的 c 只有零。

& 是按位与。结果中的每一位都是其输入中两个对应位的“与”。 01 0000 00002 和 10 0000 00002 的按位与将是 00 0000 00002

&& 是逻辑与。如果其两个操作数都非零,则其结果为 1,否则为 0。 01 0000 00002 和 10 0000 00002 的逻辑与是 1.

来自 C 标准(6.5.7 移位运算符)

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

所以在这个表达式中

c << 2

对象 c 被提升为类型 int 并且结果也具有类型 int.

由于逻辑 AND 运算符的两个操作数都不等于 0,因此整个表达式的计算结果为 1.

来自 C 标准(6.5.13 逻辑与运算符)

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

您似乎混淆了逻辑运算符 AND && 与按位运算符 AND &

如果你会写

c = (c << 2 & 512);

那么变量 c 的值为 0。

Vlad 的回答就是解释。
这是在存在提升的情况下将某些内容转化为特殊数据类型有多难的可视化:

#include <stdio.h>

int main()
{
    printf("Hello, World!\n");
    
    unsigned char c = 64;
    
    if (c <<   2 ) {printf("Yes 1.\n");}
    if (c << '') {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;
}

输出(例如这里https://www.tutorialspoint.com/compile_c_online.php):

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

您代码中的版本在 1 中失败。
尝试使用 unsigned char 操作数的版本在 2 中失败。
只有 3,操作成功覆盖提升后的显式转换。
4 时,尝试在操作再次失败之前对操作数使用显式转换。