2017-05-18 16 views
1
#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将粘贴12从输入复制到输出,当我指示它执行时var = var<<32; ???

+4

移位比数据类型中的位数多的位会导致*未定义的行为*。因此,将32位变量移位32位(或更多)是无效的。 –

+0

@Badda这不是一个有意义的重复,因为C在位移时有很多特定于语言的行为。 – Lundin

+1

[GCC左移溢出]可能重复(http://stackoverflow.com/questions/3871650/gcc-left-shift-overflow) –

回答

5

C11 6.5.7按位的移位运算符

如果右操作数的值是负的或大于或 等于推动左操作数的宽度,该行为是 未定义。

这意味着如果在这种情况下移位32位或更多位,则没有明确定义的行为。任何事情都可能发生,包括崩溃和奇怪的结果。

我从我的老书上读到的教科书上看到,ANSI C不允许在单个操作中将所有位移出值。

这是正确的,您必须执行几个操作,例如x<<=16; x<<=16;以避免未定义的行为。

+0

如果我输入'var = 12;'然后'var = var << 32;'GCC输出'12'。其他主要编译器会提供相同的输出还是完全未定义** **无论编译器是什么?如果我尝试移动太多位,我就会认为GCC编程为12。 – Mynicks

+3

@Mynicks即使在同一个编译器中,它也是完全未定义的。海湾合作委员会今天可能输出12个,明天42个,并在第二天发生事故。关键在于你不能依赖未定义的行为来给予某种行为...因此未定义。 – Lundin

+0

@Mynicks,如果在C中有_undefined behaviour_,那么它永远都是未定义的。无论如何,GCC似乎只是略过整个轮班操作,结果是未定义的(也就是无用的)。 – Gerhardh

0

GCC字面上说你回答: left shift count >= width of type [-Wshift-count-overflow]

另外它取决于你使用的架构。而你的问题已经回答了here

0

只是为了更深入一点:

经典开发为C语言“便携式汇编”。内置的操作只是大多数CPU实现的操作,它们的语义提供了可移植性的最低公分母。

几乎每个CPU都提供左移和右移操作。但是有关溢出和负数等细节的平台不同,所以C标准未定义角落案例。

特别是,对于大于寄存器宽度的移位计数,许多CPU只使用所需位数并截断其余位。当count是一个常量时,编译器可能会注意到未定义的行为,并简单地将该操作视为垃圾。