零位移位能正常工作吗?
假设我有一个这样的函数:
inline int shift( int what, int bitCount )
{
return what >> bitCount;
}
每次 bitCount
为非负且在 int
中的位数内时,都会从不同的站点调用它。 我特别担心 bitCount
等于零的调用 - 那么它能正常工作吗?
另外,编译器在编译其调用站点时看到函数的整个代码是否有可能将 bitCount
等于 0 的调用减少为无操作?
Say I have a function like this:
inline int shift( int what, int bitCount )
{
return what >> bitCount;
}
It will be called from different sites each time bitCount
will be non-negative and within the number of bits in int
. I'm particularly concerned about call with bitCount
equal to zero - will it work correctly then?
Also is there a chance that a compiler seeing the whole code of the function when compiling its call site will reduce calls with bitCount
equal to zero to a no-op?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
根据K&R“结果未定义如果右操作数为负,或者大于或等于左表达式类型中的位数。” (A.7.8) 因此
>> 0
是恒等右移并且完全合法。According to K&R "The result is undefined if the right operand is negative, or greater than or equal to the number of bits in the left expression's type." (A.7.8) Therefore
>> 0
is the identity right shift and perfectly legal.肯定至少有一个 C++ 编译器会识别这种情况(当编译时已知 0 时)并使其成为无操作:
源代码
编译器开关
英特尔 C++ 11.0 程序集
正如您在 ..B1.1 中看到的,英特尔将“return shift(42,0)”编译为“return 42”。
Intel 11 还剔除了这两种变体的移位:
对于编译时移位值未知的情况……
移位无法避免……
但至少它是内联的,因此没有调用开销。
额外的组装:挥发性是昂贵的。 源......
而不是无操作,编译为......
所以如果你正在一台机器上工作,当你弹出它们时,你压入堆栈的值可能不一样,那么,这种错过的优化可能是您遇到的最小的麻烦。
It is certain that at least one C++ compiler will recognize the situation (when the 0 is known at compile time) and make it a no-op:
Source
Compiler switches
Intel C++ 11.0 assembly
As you can see at ..B1.1, Intel compiles "return shift(42,0)" to "return 42."
Intel 11 also culls the shift for these two variations:
For the case when the shift value is unknowable at compile time ...
... the shift cannot be avoided ...
... but at least it's inlined so there's no call overhead.
Bonus assembly: volatile is expensive. The source ...
... instead of a no-op, compiles to ...
... so if you're working on a machine where values you push on the stack might not be the same when you pop them, well, this missed optimization is likely the least of your troubles.
它可以在任何广泛使用的架构上正常工作(我可以保证 x86、PPC、ARM)。 除非该函数被内联,否则编译器将无法将其减少为 noop。
It will work correctly on any widely used architecture (I can vouch for x86, PPC, ARM). The compiler will not be able to reduce it to a noop unless the function is inlined.
关于arg<<的正确性 0 或 arg>> 0,没问题,绝对没问题。
关于最终的优化:
这不会被简化为>nop<。 当使用常量 What=0 和/或 bitcount=0 调用时,除非您将其声明为内联并选择优化(并且您选择的编译器了解什么是内联)。
因此,最重要的是,只有当参数的 OR 不为零时,才通过有条件地调用函数来优化此代码(这大约是我认为测试两个参数都不为零的最快方法)。
About the correctness of arg << 0 or arg >> 0, no problem, absolutely fine.
About the eventual optimizations:
This will not be reduced to a >nop< when called with a constant what=0 and/or bitcount=0, unless you declare it as inline and choose optimizations (and your compiler of choice understands what inline is).
So, bottom line, optimize this code by conditionally calling the function only if the OR of arguments is non zero (about the fastest way I figure to test that both args are non-zero).
如果编译器在编译时知道 bitCount 值为零,则它只能执行此优化。 这意味着传递的参数必须是常量:
C++ 当然允许执行此类优化,但我不知道有任何编译器这样做。 编译器可以采取的替代方法:
在大多数情况下都是悲观的,我无法想象编译器编写者会实现这样的事情。
编辑: AA 零位移位保证对被移位的内容没有影响。
The compiler could only perform this optimisation do that if it knew at compile time that the bitCount value was zero. That would mean that the passed parameter would have to be a constant:
C++ certainly allows such an optimisation to be performed, but I'm not aware of any compilers that do so. The alternative approach the compiler could take:
would be a pessimisation in the majority of cases and I can't imagine compiler writer implementing such a thing.
Edit: AA shift of zero bits is guaranteed to have no effect on the thing being shifted.
为了使函数在某种程度上自我记录,您可能需要将 bitCount 更改为无符号,以向调用者表明负值无效。
To make the function somewhat self documenting, you may want to change bitCount to unsigned to signify to callers that a negative value is not valid.