在许多编程竞赛中,我看到人们写这种类型的for
循环。
for(i = 0; i < (1 << 7); i++)
除非我漏掉了什么,否则这就相当于
for(i = 0; i < 128; i++)
为什么要使用版本(1 << 7)
?
每次计算条件不是多余的开销吗?
在许多编程竞赛中,我看到人们写这种类型的for
循环。
for(i = 0; i < (1 << 7); i++)
除非我漏掉了什么,否则这就相当于
for(i = 0; i < 128; i++)
为什么要使用版本(1 << 7)
?
每次计算条件不是多余的开销吗?
是的,它们在行为上是等价的。
那么人们为什么使用(1 << 7)版本?
我猜,他们使用它来记录它是2的幂。
每次计算条件肯定会带来额外的开销!我找不到背后的原因!
实际上不会有开销,任何正常的编译器都会将1 << 7
替换为128
,因此两个循环的性能相同。
(C11, 6.6p2)"常量表达式可以在编译时而非运行时进行评估,并且因此可能在任何可以使用常量的地方使用。"
?:
运算符以非常强大的方式传播)。因此,在编译时完全评估所有常量表达式没有不好的理由。 - R.. GitHub STOP HELPING ICEintmax_t
或 uintmax_t
)。控制常量表达式的 #if
必须在预处理时(更具体地说是在第四个翻译阶段)进行评估(例如,在 #if 1 << 7 == 128
中)。@YvesDaoust @Echelon - ouah让我们将这些选项中的每一个翻译成简单易懂的英语:
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
两种情况的运行行为应该是相同的。
实际上,假设编译器足够好,即使汇编代码也应该是相同的。
因此,第一种选项本质上只是用来“表明立场”的。
你完全可以使用第二个选项并在上面添加注释。
i
。i
倾向于表示“我正在处理的索引”,但程序员想要表达的是“我正在处理的模式”。像 bitCombo
这样的名称可以在没有注释的情况下清晰地表达意思。比赛往往强调简短和巧妙而不是清晰,所以也许他们坚持使用 i
来保持神秘感。 - Mirinth1 << 7
是一个常量表达式,编译器会将其视为 128
,运行时没有任何开销。
没有循环体,很难说作者为什么使用它。可能是一个与7位相关的迭代循环,但这只是我的猜测。
那么为什么人们使用 (1 << 7) 版本?
这是一种文档形式,不是一个神奇数字,而是对于编写代码的人来说有意义的2的7次方(two to the seventh power)。现代优化编译器应该为两个示例生成完全相同的代码,因此使用这种形式没有成本,并且增加了上下文信息。
使用 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
对于循环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的幂变化的状态。但是只有当你的算法需要这个逻辑时才适用。
NUM_STEPS
或NUM_ELEMENTS_IN_NETWORK_PACKET
以清晰地表达。128
来表明它是一个常量。1 << 7
。或者,您可以炫耀自己知道位操作!
在我看来,编程就像为两个人编写信件,编译器和将要阅读它的人。您的意思应该对两者都清楚。
由于两个操作数都是常量,因此它由预处理器评估。
但是,如果您要使用数字而不是位移,那么应该是0x0100吗?
128
会让它看起来像是一个不可解释的“魔法常数”。写(1 << 7)
会让人立刻明白这个常数代表什么以及它来自哪里。最好采用这种方式。 - AnT stands with Russiafor(i = 0; i < NUMBER_OF_STEPS; i++)
,不要使用魔法数字。 - glampertfor(i = 0; i < ONE_HUNDRED_TWENTY_EIGHT; i++)
。我称之为 _魔法常量_!。 - rodrigo