为什么表达式而不是常量,在C for循环的条件中?

时间:2014-08-30 11:58:08

标签: c for-loop coding-style expression constantfolding

在许多编程比赛中,我看到有人写这种for - 循环

for(i = 0; i < (1 << 7); i++)

除非我遗漏了某些内容,否则与

相同
for(i = 0; i < 128; i++)

为什么要使用(1 << 7)版本?
每次不必要的开销都不计算条件吗?

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我们可以验证确实如此,至少对于gccclangicc的多个版本都是如此。使用一个带副作用的简单示例来确保代码没有完全优化:

#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)

编译器为两种情况输出相同的代码。你可能想根据具体情况使用不同的形式。

  1. 如果您希望明确算法中的常量部分或设计选项,则可以使用NUM_STEPSNUM_ELEMENTS_IN_NETWORK_PACKET
  2. 或者你可以写128,以明确它128,一个常数。
  3. 或者如果您正在参加比赛,请写1 << 7并且测试说“运行2 ^ 7次
  4. 或者,你可以炫耀你知道位操作!

    在我看来,编程就像为两个人写一封信,编译器和必须阅读它的人。对于两者而言,你的意思应该是明确的。

答案 6 :(得分:-3)

由预处理器评估,因为两个操作数都是常量。

但如果你要使用数字代替比特移位不应该是0x0100?