在许多编程比赛中,我看到人们编写这种类型的for
-loop
for(i = 0; i < (1 << 7); i++)
除非我遗漏了什么,否则这与
for(i = 0; i < 128; i++)
为什么要使用(1 << 7)
版本?
每次计算条件不是不必要的开销吗?
在许多编程比赛中,我看到人们编写这种类型的for
-loop
for(i = 0; i < (1 << 7); i++)
除非我遗漏了什么,否则这与
for(i = 0; i < 128; i++)
为什么要使用(1 << 7)
版本?
每次计算条件不是不必要的开销吗?
是的,它们在行为上是等效的。
那为什么人们使用 (1 << 7) 版本呢?
我想,他们用它来记录它是 2 的幂。
每次计算条件一定是开销!我无法找到这背后的原因!
并非如此,任何普通编译器都将替换1 << 7
为128
,因此两个循环将具有相同的性能。
(C11, 6.6p2) “常量表达式可以在翻译期间而不是运行时进行评估,因此可以在常量可能存在的任何地方使用。”
让我们将这些选项中的每一个都翻译成简单的英语:
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
两种情况下的运行时行为应该相同。
事实上,假设一个像样的编译器,即使是汇编代码也应该是相同的。
所以第一个选项本质上只是为了“发表声明”。
您也可以使用第二个选项并在上面添加评论。
1 << 7
是一个常量表达式,编译器将其视为128
,运行时没有开销。
没有循环体,很难说作者为什么要用它。可能它是一个循环迭代与 7 位相关的东西,但这只是我的猜测。
那为什么人们使用 (1 << 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 ) ;
}
}
对于代码的相关部分,我们可以看到它们都生成以下内容:
cmpl $128, %ebx
我们所拥有的是一个整数常量表达式,如 C11 标准草案中定义的6.6
常量表达式部分所述:
整数常量表达式 117) 应具有整数类型,并且应仅具有整数常量、枚举常量、字符常量、结果为整数常量的表达式 sizeof 的操作数,[...]
和:
常量表达式不应包含赋值、递增、递减、函数调用或逗号运算符,除非它们包含在未计算的子表达式中。115)
我们可以看到在翻译过程中允许对常量表达式求值:
常量表达式可以在翻译期间而不是运行时进行评估,因此可以在常量可能存在的任何地方使用。
for(i = 0; i < (1 << 7); i++)
和
for(i = 0; i < 128; i++)
提供相同的性能,但开发人员可以在循环中使用 for(i = 0; i < (1 << 7); i++) 作为
for(int k = 0; k < 8; k++)
{
for(int i = 0; i < (1 << k); i++)
{
//your code
}
}
现在它处于内部循环上限,即 (1 << k) 随着 2 运行时的幂的变化而变化。但如果您的算法需要此逻辑,则它适用。
The compiler outputs the same code for both cases. you probably want to use different forms depending on the context.
NUM_STEPS
or NUM_ELEMENTS_IN_NETWORK_PACKET
when it's a constant part or a design choice in your algorithm that you want to make clear.128
, to make clear it's 128
, a constant.1 << 7
if you're at a competition and the test said something like "run it 2^7 times".Or, you can be showing off that you know bit operations!
In my humble opinion, programming is like writing a letter for two people, the compiler and the person that will have to read it. What you're meaning should be clear for both.
它由预处理器评估,因为两个操作数都是常数。
但是如果你要使用数字而不是位移,它不应该是 0x0100 吗?