轮班计数操作允许使用哪些值?
what values are allowed for the shift count operation?
#include <stdio.h>
int main(void)
{
unsigned int var=1;
var = var<<32;
printf("%u ",var);
}
此代码输出 1
。如果我写 var = var<<31;
它会产生 2147483648
.
如果我输入 var = 12;
然后 var = var<<32;
它会产生 12
。我从我的旧教科书中读到,ANSI C 不允许在一次操作中将所有位从一个值中移出。
所有主要编译器的行为是否相同(将输入复制粘贴到输出),或者当我指示 GCC 执行操作时,GCC 确实将粘贴 12 从输入复制到输出 var = var<<32;
???
C11 6.5.7 移位运算符
If the value of the right operand is negative or is greater than or
equal to the width of the promoted left operand, the behavior is
undefined.
这意味着如果您在这种情况下移动 32 位或更多位,则没有明确定义的行为。任何事情都可能发生,包括崩溃和奇怪的结果。
I read from my textbook, an old one, that ANSI C does not allow to shift all the bits out of a value in a single operation.
这是正确的,您必须执行多个位操作,例如 x<<=16; x<<=16;
以避免未定义的行为。
GCC 字面上说你回答:
left shift count >= width of type [-Wshift-count-overflow]
.
这也取决于您使用的架构。您的问题已经得到解答 here.
更深入一点:
经典的 C 语言开发为 "portable assembler." 内置操作只是大多数 CPU 实现的操作,它们的语义为可移植性提供了最低公分母。
几乎每个 CPU 都提供左移和右移操作。但是平台在溢出和负数等细节方面存在差异,因此 C 标准未定义极端情况。
特别是,对于大于寄存器宽度的移位计数,许多 CPU 仅使用所需的位并截断其余位。当计数是常量时,编译器可能会注意到未定义的行为,并简单地将操作作为垃圾丢弃。
#include <stdio.h>
int main(void)
{
unsigned int var=1;
var = var<<32;
printf("%u ",var);
}
此代码输出 1
。如果我写 var = var<<31;
它会产生 2147483648
.
如果我输入 var = 12;
然后 var = var<<32;
它会产生 12
。我从我的旧教科书中读到,ANSI C 不允许在一次操作中将所有位从一个值中移出。
所有主要编译器的行为是否相同(将输入复制粘贴到输出),或者当我指示 GCC 执行操作时,GCC 确实将粘贴 12 从输入复制到输出 var = var<<32;
???
C11 6.5.7 移位运算符
If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.
这意味着如果您在这种情况下移动 32 位或更多位,则没有明确定义的行为。任何事情都可能发生,包括崩溃和奇怪的结果。
I read from my textbook, an old one, that ANSI C does not allow to shift all the bits out of a value in a single operation.
这是正确的,您必须执行多个位操作,例如 x<<=16; x<<=16;
以避免未定义的行为。
GCC 字面上说你回答:
left shift count >= width of type [-Wshift-count-overflow]
.
这也取决于您使用的架构。您的问题已经得到解答 here.
更深入一点:
经典的 C 语言开发为 "portable assembler." 内置操作只是大多数 CPU 实现的操作,它们的语义为可移植性提供了最低公分母。
几乎每个 CPU 都提供左移和右移操作。但是平台在溢出和负数等细节方面存在差异,因此 C 标准未定义极端情况。
特别是,对于大于寄存器宽度的移位计数,许多 CPU 仅使用所需的位并截断其余位。当计数是常量时,编译器可能会注意到未定义的行为,并简单地将操作作为垃圾丢弃。