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

哪个更快?

while(1) {
    // Some code
}

or

while(2) {
    //Some code
}

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

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

这是真的吗?

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


当前回答

为了这个问题,我应该补充一点,我记得C委员会的Doug Gwyn写过,一些早期的C编译器如果没有优化器通道,会在汇编中生成一个while(1)的测试(相比之下,For(;;)没有它)。

我会给出这个历史笔记来回答面试官,然后说,即使我对任何编译器这样做感到非常惊讶,编译器也可以这样做:

没有优化器,通过编译器生成while(1)和while(2)测试 通过优化器传递,编译器被指示优化(无条件跳转),而(1),因为它们被认为是惯用的。这将使while(2)只剩下一个测试,从而导致两者之间的性能差异。

当然,我要向面试官补充的是,不考虑while(1)和while(2)相同的结构是低质量优化的标志,因为它们是等效的结构。

其他回答

因为回答这个问题的人希望得到最快的循环,所以我的回答是,两者都是同样地编译成相同的汇编代码,正如在其他答案中所述。不过,你可以用“循环展开”向面试官建议;一个do {} while循环而不是while循环。

谨慎:您需要确保循环至少总是运行一次。

循环内部应该有一个中断条件。

同样,对于这种循环,我个人更喜欢使用do {} while(42),因为除了0之外,任何整数都可以完成这项工作。

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

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

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

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

显而易见的答案是:正如所发布的,两个片段将运行一个同样繁忙的无限循环,这使得程序无限慢。

虽然从技术上讲,将C关键字重新定义为宏将具有未定义的行为,但这是我能想到的使任何一个代码片段快速的唯一方法:你可以在两个片段之上添加这一行:

#define while(x) sleep(x);

它确实会使while(1)比while(2)快一倍(或慢一半)。

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.

现有的答案显示了由特定编译器为特定目标使用特定选项集生成的代码,并不能完全回答这个问题——除非在特定的上下文中提出了这个问题(例如,“对于带有默认选项的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网站的好问题)。