【问题标题】:Is it legal to static_assert that signed shift right has two's-complement behavior?static_assert 签名右移具有二进制补码行为是否合法?
【发布时间】:2014-10-20 20:24:27
【问题描述】:

在 C11、C++11 和 C++14 中执行以下操作是否合法?

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");

我不知道关于是否可以使用上述实现定义的操作的常量表达式规则。

我知道,无论机器类型如何,负数的相反的有符号左移是未定义的。

【问题讨论】:

  • 考虑在你的代码中使用/ 来完全避免这个问题。无论班次定义如何,(-4) / 2 始终为 -2
  • @Matt:虽然,它有向零舍入,而移位硬件经常向下舍入。所以它很容易以非常慢的速度结束,也许四舍五入是我们想要的。
  • @MattMcNabb:我的代码滥用签名>> 的原因是我可以在高位构建掩码。例如,x >> 31 等价于 x < 0 ? -1 : 0。当然,编译器已经为您进行了优化,但有时它看到它在做什么。此外,这是在我的代码中非常热门的部分完成的。
  • @Myria 尝试检查编译器在最大优化级别生成的程序集,看看这是否真的是一个问题。在我的带有gcc -O3 的系统上,它对两者都有sarl $31, %eax。最大便携性和最大速度通常是相互矛盾的目标。
  • 对于它的价值,即使编译器不支持它,编写一个宏来执行算术,二进制补码右移也是微不足道的,任何好的优化编译器都会崩溃到只是对自然具有您想要的行为的目标进行正常转变。

标签: c++ c c++11 language-lawyer c11


【解决方案1】:

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

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

并且在 [expr.const]/2 中没有任何地方说这种移位或具有实现定义值的表达式通常不是常量表达式。 因此,您将获得一个具有实现定义值的常量表达式。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 只有在值开始为负时才由实现定义。
    • 这是关键,您应该进行不止一项测试以确保您获得所需的行为。
    • @chris:在这个问题上,确实如此。
    • @BenVoigt,这只是答案的措辞,听起来像是每个输入的 ID。
    猜你喜欢
    • 2017-01-29
    • 1970-01-01
    • 2015-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-14
    • 2022-01-24
    • 2018-03-25
    相关资源
    最近更新 更多