看看这个例子:
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 只有零。
看看这个例子:
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 只有零。
来自 C 标准(6.5.7 位移位运算符)
3 对每个操作数执行整数提升。结果的类型是提升的左操作数的类型。
所以在这个表达式中
c << 2
对象 c 被提升为 typeint
并且结果也具有 type int
。
由于逻辑 AND 运算符的两个操作数都不等于,0
因此整个表达式的计算结果为1
。
来自 C 标准(6.5.13 逻辑与运算符)
3 如果 && 运算符的两个操作数比较不等于 0,则 && 运算符将产生 1;否则,它产生 0。结果具有 int 类型。
您似乎将逻辑运算符 AND&&
与按位运算符 AND混淆了&
。
如果你会写
c = (c << 2 & 512);
那么变量c
的值为0。
&
是按位与。结果中的每一位都是其输入中两个对应位的与。01 0000 0000 2和 10 0000 0000 2的按位与将是 00 0000 0000 2。
&&
是逻辑与。如果两个操作数都不为零,则其结果为 1,否则为 0。01 0000 0000 2和 10 0000 0000 2的逻辑与为 1。
弗拉德的答案是解释。
这是一个可视化,在存在提升的情况下将某些东西放入特殊数据类型是多么困难:
#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;
}
输出(例如这里https://www.tutorialspoint.com/compile_c_online.php):
Hello, World!
Yes 1.
Yes 2.
No 3.
Yes 4.
您的代码中的版本在 1 中失败。
尝试使用 unsigned char 操作数的版本在 2 中失败。
只有 3,操作后的显式转换设法覆盖提升。
While 4,尝试在操作之前对操作数使用显式强制转换再次失败。