这是一位高级经理在面试时问的问题。

哪个更快?

while(1) {
    // Some code
}

or

while(2) {
    //Some code
}

我说过两者具有相同的执行速度,因为while中的表达式最终应求值为true或false。在这种情况下,两者都求值为true,并且while条件中没有额外的条件指令。因此,两者将具有相同的执行速度,我更喜欢while(1)。

但面试官自信地说: “检查你的基本知识。While(1)比While(2)快。” (他不是在试探我的信心)

这是真的吗?

请参见:“for(;;)”是否比“while (TRUE)”快?如果不是,人们为什么要使用它?


当前回答

现有的答案显示了由特定编译器为特定目标使用特定选项集生成的代码,并不能完全回答这个问题——除非在特定的上下文中提出了这个问题(例如,“对于带有默认选项的x86_64,使用gcc 4.7.2哪个更快?”)。

就语言定义而言,在抽象机器中while(1)计算整数常数1,while(2)计算整数常数2;在这两种情况下,比较结果是否等于零。语言标准完全没有说明这两种构造的相对性能。

我可以想象,一个极其幼稚的编译器可能会为这两种表单生成不同的机器代码,至少在编译时没有请求优化。

另一方面,C编译器绝对必须在编译时计算一些常量表达式,当它们出现在需要常量表达式的上下文中时。例如,这个:

int n = 4;
switch (n) {
    case 2+2: break;
    case 4:   break;
}

需要诊断;延迟编译器没有将2+2的计算延迟到执行时的选项。由于编译器必须具备在编译时计算常量表达式的能力,因此即使不需要也没有充分的理由不利用这种能力。

C标准(N1570 6.8.5p4)说

一个迭代语句导致一个称为循环体的语句 重复执行,直到控制表达式比较为 0.

所以相关的常数表达式是1 == 0和2 == 0,它们的值都是int值0。(这些比较隐含在while循环的语义中;它们并不作为实际的C表达式存在。)

非常简单的编译器可能会为这两种构造生成不同的代码。例如,对于第一个,它可以生成一个无条件的无限循环(将1视为特殊情况),对于第二个,它可以生成一个显式的运行时比较,等价于2 != 0。但我从来没有遇到过这样的C编译器,我严重怀疑这样的编译器是否存在。

大多数编译器(我倾向于说所有生产质量的编译器)都有请求额外优化的选项。在这种选择下,任何编译器都不太可能为这两种表单生成不同的代码。

如果编译器为这两种构造生成不同的代码,首先检查不同的代码序列是否具有不同的性能。如果有,请尝试使用优化选项(如果可用)再次编译。如果它们仍然不同,则向编译器供应商提交错误报告。这(不一定)是一个不符合C标准的错误,但几乎可以肯定这是一个应该纠正的问题。

底线:while(1)和while(2)几乎肯定具有相同的性能。它们具有完全相同的语义,任何编译器都没有理由不生成相同的代码。

尽管编译器为while(1)生成比while(2)更快的代码是完全合法的,但在同一个程序中,编译器为while(1)生成比另一个while(1)更快的代码也是合法的。

(你问的问题中还暗含着另一个问题:你如何应对坚持提出一个错误的技术观点的面试官?这可能是一个适合Workplace网站的好问题)。

其他回答

看到这么多人深入研究这个问题,正好说明了为什么这可以很好地作为一个测试,看看您想要多快地进行微优化。

我的答案是;这并不重要,我更关注我们正在解决的业务问题。毕竟,这就是我的工作。

此外,我会选择while(1){},因为它更常见,其他队友不需要花时间去弄清楚为什么有人会选择比1更高的数字。

现在去写一些代码。: -)

You should have asked him how did he reached to that conclusion. Under any decent compiler out there, the two compile to the same asm instructions. So, he should have told you the compiler as well to start off. And even so, you would have to know the compiler and platform very well to even make a theoretical educated guess. And in the end, it doesn't really matter in practice, since there are other external factors like memory fragmentation or system load that will influence the loop more than this detail.

这里有一个问题:如果您实际编写一个程序并测量它的速度,两个循环的速度可能是不同的!以下是一些合理的比较:

unsigned long i = 0;
while (1) { if (++i == 1000000000) break; }

unsigned long i = 0;
while (2) { if (++i == 1000000000) break; }

添加了一些打印时间的代码后,一些随机的效果(比如循环在一条或两条缓存线中的位置)可能会产生影响。一个循环可能完全位于一条缓存线内,或者位于一条缓存线的开头,或者它可能横跨两条缓存线。因此,面试官说最快的可能真的是最快的——纯属巧合。

最坏的情况:优化编译器不知道循环做了什么,但知道执行第二个循环时产生的值与第一个循环产生的值相同。并为第一个循环生成完整代码,但不为第二个循环生成完整代码。

它们是相等的。

根据规范,任何不为0的都被认为是真的,所以即使没有任何优化,一个好的编译器也不会生成任何代码 For while(1) or while(2)。编译器将生成一个简单的检查!= 0。

我能想到为什么while(2)会更慢的唯一原因是:

代码将循环优化为 2 . CMP eax 当减法发生时,你实际上是在减法 A. 00000000 - 00000010 CMP eax, 2 而不是 B. 00000000 - 00000001 CMP eax, 1

CMP只设置标志,不设置结果。所以对于最低有效位,我们知道b是否需要借位,而对于a,你必须做两次减法才能得到借位。