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

哪个更快?

while(1) {
    // Some code
}

or

while(2) {
    //Some code
}

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

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

这是真的吗?

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


当前回答

根据人们花费在测试、证明和回答这个非常直接的问题上的时间和精力来判断,我认为这两者都因为提出这个问题而变得非常缓慢。

所以花更多的时间在这上面…

虽然(2)很荒谬,因为,

While(1)和While (true)在历史上被用于创建一个无限循环,该循环预计在循环中的某个阶段根据一定会发生的条件调用break。

1只是为了总是求值为真,因此,说while(2)和说while(1 + 1 == 2)一样愚蠢,后者也会求值为真。

如果你想完全傻一点,就用:-

while (1 + 5 - 2 - (1 * 3) == 0.5 - 4 + ((9 * 2) / 4.0)) {
    if (succeed())
        break;
}

我认为面试官犯了一个错别字,这并不影响代码的运行,但如果他故意使用2只是为了表现得奇怪,那么在他把奇怪的语句贯穿你的代码,使其难以阅读和使用之前解雇他。

其他回答

对这个问题最有可能的解释是,面试官认为处理器会逐一检查数字的每一位,直到它达到一个非零值:

1 = 00000001
2 = 00000010

如果“is 0 ?”算法从数字的右侧开始,并且必须检查每一位直到它达到非零位,那么while(1){}循环每次迭代必须检查的比特数是while(2){}循环的两倍。

这需要一个关于计算机如何工作的非常错误的思维模型,但它确实有自己的内部逻辑。一种检查方法是询问while(-1){}或while(3){}是否同样快,或者while(32){}是否更慢。

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

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

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

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

它们是相等的。

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

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

在我看来,这是一个被伪装成技术问题的行为面试问题。有些公司会这样做——他们会问一个任何有能力的程序员都应该很容易回答的技术问题,但是当面试者给出正确答案时,面试官会告诉他们他们错了。

公司想看看你在这种情况下会作何反应。你是否会因为自我怀疑或害怕让面试官不高兴而安静地坐在那里,不强调自己的答案是正确的?或者你愿意挑战一个你知道是错误的权威人士吗?他们想看看你是否愿意坚持自己的信念,以及你是否能以一种机智和尊重的方式做到这一点。