57

在许多编程比赛中,我看到人们编写这种类型的for-loop

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

除非我遗漏了什么,否则这与

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

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

4

7 回答 7

76

是的,它们在行为上是等效的。

那为什么人们使用 (1 << 7) 版本呢?

我想,他们用它来记录它是 2 的幂。

每次计算条件一定是开销!我无法找到这背后的原因!

并非如此,任何普通编译器都将替换1 << 7128,因此两个循环将具有相同的性能。

(C11, 6.6p2) “常量表达式可以在翻译期间而不是运行时进行评估,因此可以在常量可能存在的任何地方使用。”

于 2014-08-30T12:03:59.743 回答
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

两种情况下的运行时行为应该相同。

事实上,假设一个像样的编译器,即使是汇编代码也应该是相同的。

所以第一个选项本质上只是为了“发表声明”。

您也可以使用第二个选项并在上面添加评论。

于 2014-08-30T12:23:08.090 回答
19

1 << 7是一个常量表达式,编译器将其视为128,运行时没有开销。

没有循环体,很难说作者为什么要用它。可能它是一个循环迭代与 7 位相关的东西,但这只是我的猜测。

于 2014-08-30T12:04:11.867 回答
14

那为什么人们使用 (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)

我们可以看到在翻译过程中允许对常量表达式求值:

常量表达式可以在翻译期间而不是运行时进行评估,因此可以在常量可能存在的任何地方使用。

于 2014-08-31T01:05:10.880 回答
5

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 运行时的幂的变化而变化。但如果您的算法需要此逻辑,则它适用。

于 2014-08-30T12:41:54.483 回答
3

The compiler outputs the same code for both cases. you probably want to use different forms depending on the context.

  1. You can use 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.
  2. Or you can write 128, to make clear it's 128, a constant.
  3. Or write 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.

于 2014-09-01T12:23:11.313 回答
-3

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

但是如果你要使用数字而不是位移,它不应该是 0x0100 吗?

于 2014-09-03T08:26:25.757 回答