2016-05-25 21 views
1

我的代码的目的是在我的int(32位)表示的右侧创建n个零的掩码。我的方法是首先将负数存储在一个变量中,然后将其左移n个空格,以便右边有n个零。代码如下:为什么我在左移位的不同实现中有这种不同的行为?

int mask(int n){ 
    int neg1=(1<<31)>>31; 
    int mask=neg1<<n; 
    return mask; 
} 

然而当n为32,我想获得价值为0x0,而是我得到的0xffffffff(NEG1)。当我切换到变量时会发生这种情况。但是,当我转向常数本身时,它就像一种魅力。新代码是:

mask=0xffffffff<<n; 

尽管如此,我不允许使用多于8位的常量。所以我需要存储在另一个变量中的值。有人可以告诉我为什么会发生这种情况,我该如何解决?

非常感谢!

+2

你正在试图做的换挡是未定义的行为。另外,为什么你要做'(1 <<31)>> 31'(也是未定义的行为)来获得'-1'? – user2357112

+0

注意:左移入符号位是UB。“实现定义的行为的一个例子是如果一个有符号整数右移,就会出现高位“so'int neg1 =(1 <<31)>> 31;'可能无法按预期执行 – chux

+3

必须使用'int'吗?'unsigned'如何? – chux

回答

1

OP的代码在尝试向左移入32位int的符号位时调用未定义的行为。

E1的结果< < E2是E1左移E2位位置;空位填充零。 ...如果E1具有带符号的类型和非负值,并且E1×2E2可以在结果类型中表示,那么这是结果值;否则,行为是不确定的。 C11§6.5.74

而是使用无符号类型,以避免与的31的移位不明确的行为的32+上的32位unsigned的移位将是一个问题了。

一个简单的方法使用更广泛的类型。

#include <stdio.h> 
#include <inttypes.h> 

uint32_t mask32(int n) { 
    return 0 - (1ull << n); 
} 

int main(void) { 
    for (int i=0; i<=32; i++) { 
    printf("%2d %lX\n", i, (unsigned long) mask32(i)); 
    } 
} 

输出

0 FFFFFFFF 
1 FFFFFFFE 
2 FFFFFFFC 
... 
29 E0000000 
30 C0000000 
31 80000000 
32 0 
+0

非常感谢你!我只是不知道这是一个未定义的行为。虽然这很奇怪,当我用一个常量来做这件事时,我得到了我想要的东西,当用一个变量做这件事时,我得到了另一件事! –

+1

@Aldo Pareja在声明中不清楚“用一个常量来做这件事,我得到了我想要的东西,并用变量做这件事”。具有32位'int'的细节'1 << 31'是UB,因为1('int')被移入符号位。 '0xffffffff'是一个'unsigned',并且将一个32位的'unsigned'由0移到31是很好的定义。 – chux

相关问题