2014-10-20 5 views
3

在C11,C++ 11和C++ 14中执行以下操作是否合法?static_assert是否合法,签名的右移是否具有二进制补码行为?

static_assert(((-4) >> 1) == -2, "my code assumes sign-extending right shift"); 

或等价的C:

_Static_assert(((-4) >> 1) == -2, "my code assumes sign-extending right shift"); 

我不知道关于你是否可以使用实现定义的操作,如上述的等速表达式的规则。

我知道,负数的左边相反的带符号左移是不确定的,与机器类型无关。

+0

考虑在代码中使用'/'来完全避免这个问题。无论换档定义如何,(-4)/ 2'总是“-2”。 – 2014-10-20 20:31:27

+0

@Matt:虽然它已经趋于零,而换挡硬件经常是四舍五入的。所以很容易就会变得非常缓慢,也许轮到的就是想要的。 – 2014-10-20 20:33:22

+0

@MattMcNabb:我的代码滥用符号“>>”的原因是我可以在高位构建一个掩码。例如,'x >> 31'等价于'x <0? -1:0'。当然,编译器已经为你做了这种优化,但有时它*不会*看到它在做什么。此外,这是在我的代码中非常热的部分完成的。 – Myria 2014-10-20 20:36:09

回答

6

是的。在C++ 11标准说,在[expr.shift]/3:

E1 >> E2值是E1右移E2比特位置。如果 E1具有无符号类型,或者E1具有带符号的类型和非负的 值,则结果的值是 E1/2^E2的商的整数部分。 如果E1具有带符号类型和负值,则结果值是实现定义的。

而无处在[expr.const]/2这是说,一般说来,这样的转变,或者用实现定义的值的表达式,不是常量表达式。 您将因此得到一个具有实现定义值的常量表达式。

3

这是合法的,因为它不会导致未定义的行为。

负值的右移行为是实现定义的。 C和C++标准不能保证它是算术或逻辑的;尽管据我所知,从来没有一个CPU没有选择其中的一个。

+2

只有实现才会定义,如果该值开始为负数 – chris 2014-10-20 20:29:07

+0

这是关键,您应该有一个以上的测试你正在得到你需要的行为 – 2014-10-20 20:29:34

+0

@chris:在这个问题中,它确实如此。 – 2014-10-20 20:29:53