在许多编程比赛中,我看到有人写这种for
- 循环
for(i = 0; i < (1 << 7); i++)
除非我遗漏了某些内容,否则与
相同for(i = 0; i < 128; i++)
为什么要使用(1 << 7)
版本?
每次不必要的开销都不计算条件吗?
答案 0 :(得分:76)
是的,他们的行为相同。
那么为什么人们使用(1&lt;&lt;&lt;&lt;&lt;&#7)版本?
我猜,他们用它来证明它是2的力量。
每次计算条件必须是开销!我无法找到背后的原因!
不是真的,任何普通的编译器都会用1 << 7
替换128
,因此两个循环都会有相同的性能。
(C11,6.6p2)“可以在翻译期间而不是运行时评估常量表达式,因此可以在常量可能的任何位置使用。”
答案 1 :(得分:31)
让我们将这些选项中的每一个翻译成普通英语:
for(i = 0; i < (1 << 7); i++) // For every possible combination of 7 bits
for(i = 0; i < 128; i++) // For every number between 0 and 127
两种情况下的运行时行为应该相同。
事实上,假设一个合适的编译器,即使汇编代码也应该是相同的。
所以第一个选项主要是为了#34;发表声明&#34;。
您也可以使用第二个选项并在上面添加评论。
答案 2 :(得分:19)
1 << 7
是一个常量表达式,编译器将其视为128
,运行时没有开销。
没有循环体,很难说为什么作者使用它。可能它是一个迭代与7位相关的东西的循环,但这只是我的猜测。
答案 3 :(得分:14)
那么人们为什么要使用(1&lt;&lt;&lt;&lt;&lt;&#7)版本?
这是一种文档形式,它不是一个神奇的数字,而是2^7
(二到七次幂),这对编写代码的人来说都是有意义的。现代优化编译器应为两个示例生成完全相同的代码,因此使用此表单无需任何成本,并且可以添加上下文。
使用godbolt我们可以验证确实如此,至少对于gcc
,clang
和icc
的多个版本都是如此。使用一个带副作用的简单示例来确保代码没有完全优化:
#include <stdio.h>
void forLoopShift()
{
for(int i = 0; i < (1 << 7); i++)
{
printf("%d ", i ) ;
}
}
void forLoopNoShift()
{
for(int i = 0; i < 128; i++)
{
printf("%d ", i ) ;
}
}
对于代码的相关部分,我们可以看到它们都生成以下see it live:
cmpl $128, %ebx
我们所拥有的是整数常量表达式,如草案C11标准部分6.6
常量表达式中所定义:
整数常量表达式117)应具有整数类型且仅具有操作数 它是整数常量,枚举常量,字符常量,sizeof 结果为整数常量的表达式,[...]
和
常量表达式不应包含赋值,递增,递减,函数调用, 或逗号运算符,除非它们包含在不是的子表达式中 evaluated.115)
我们可以看到在翻译期间允许评估常量表达式:
可以在转换期间而不是运行时评估常量表达式 因此可以在常数可能的任何地方使用。
答案 4 :(得分:5)
for(i = 0; i&lt;(1 <7); i ++)
和
表示(i = 0; i <128; i ++)
具有相同的性能但是开发人员可以在(i = 0; i&lt;(1&lt;&lt; 7); i ++)在循环中使用
的情况下获得巨大的优势for(int k = 0; k < 8; k++)
{
for(int i = 0; i < (1 << k); i++)
{
//your code
}
}
现在它处于内循环上限,即(1 <&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; k)随着2运行时的功率而变化。但如果您的算法需要这种逻辑,它就适用。
答案 5 :(得分:3)
编译器为两种情况输出相同的代码。你可能想根据具体情况使用不同的形式。
NUM_STEPS
或NUM_ELEMENTS_IN_NETWORK_PACKET
。128
,以明确它128
,一个常数。1 << 7
并且测试说“运行2 ^ 7次。或者,你可以炫耀你知道位操作!
在我看来,编程就像为两个人写一封信,编译器和必须阅读它的人。对于两者而言,你的意思应该是明确的。
答案 6 :(得分:-3)
由预处理器评估,因为两个操作数都是常量。
但如果你要使用数字代替比特移位不应该是0x0100?