(x==0)比(0==x)更有效吗?

3

可能是重复问题:
if(flag==0)和if(0==flag),哪个会更快执行?

我通常将我的等式条件写成:

if(0==x)

像许多人一样,而不是

if(x==0) 

为了让编译器在我意外输入 = 而不是 == 时告诉我。

有人告诉我,某些编译器将其实现为两个寄存器加载,而不是使用非零操作的一个,因此效率较低。

有人知道这是否是一个合理的评论吗?


13
打开您的编译器警告,并在为时已晚之前以自然语言书写(x == 0)! - GManNickG
4
“as many people do” - 我不这么认为。 - Xeo
4
请确认这个“某人”的身份。 - user2100815
1
@Zaur:除了英语以外的语言是被禁止的。 ;) - GManNickG
5
@Xeo,这是一种古老而广为人知的技术,因此“很多人”是完全公平的表述。 - DNA
显示剩余3条评论
5个回答

9
有人告诉我,一些编译器将其实现为两个寄存器加载,而不是使用非零操作的一个。
没有技术上的理由这样做。因此,任何值得一试的编译器都不会做出这种无关紧要的区分:由于两个语句严格等价,并且由于编译器可以轻松地识别它们,因此它们被视为相同。
请注意,这仅适用于内置类型和具有良好行为的用户定义类型的operator ==。理论上,用户可能提供了一个不对称的operator ==重载,其中这种等价性并未给出。

3
谎言! struct x {}; bool operator==(x, int) { return true; } bool operator==(int, x) { for (volatile int i = 1; i != 0;); }. :P 编辑:啊,你已经偷偷编辑了。:(注意:此段话是程序员开玩笑的一种方式。它定义了两个不同类型之间的相等运算符,但其中一个运算符会导致无限循环。最后的 ":P" 表示这是一个吐舌头的表情符号,用于增加幽默感。 - GManNickG
@GMan:我喜欢那种重载的想法,可以阻止人们做Yoda条件! - Xeo

4

谁知道“一些编译器”具体做了什么,但通常情况下,我不会期望任何合理编译器生成的代码有任何区别。


0

试着编写一些小程序,比如下面的例子,你可以确定哪个适合你的需求。你是想要小代码尺寸还是快速执行?

#include <stdio.h>
#include <stdlib.h>

    int main(int argc, char *argv[]) {
        int x = atoi(argv[1]);
        int zeros=0;
        int i;
        for (i=0; i<100000; i++) {
            if (0==x) {
                zeros++;
            }
        }
        printf("zeros: %d\n",zeros);
        return 0;
    }

在我的机器上,gcc会生成一个比(x==0)的方法小两个字节的可执行文件;然而第二种方法的执行时间更快。 - levis501
使用-O4优化标志,两种方法在速度方面表现相同,即使将循环大小增加到10000000。 (0 == x)的方式具有较小的可执行文件大小。 - levis501
与非优化构建比较程序大小或执行时间毫无意义。 - MSalters
@MSalters:出于教学目的 - levis501
你的“基准测试”使用GCC和clang进行优化,生成的汇编代码相当于zeros = x ? 0 : 100000,而不是循环。https://godbolt.org/z/qG8TnnEa5。如果你只想查看汇编代码,那么有更简单的测试函数可供查看,无需进行无意义的循环。 - Peter Cordes

0

我不这么认为。编译器会将该表达式解释为比较,效果是相同的。如果编译器足够聪明,它会检测到0可以被优化。

当你有多个比较时,重要的是注意比较的顺序:

if(conditionA && conditionB && (conditionC || conditionD)) {...}

在这种情况下,你应该将条件A设置为导致if尽快失败的条件,而不是让执行分析所有其他条件,然后才发现条件A失败。

-1
为什么不尝试对这两个解决方案进行基准测试呢?

#include <stdio.h>
#include <time.h>

#define LOOPS   1000000000

void main(void)
{
    clock_t start1, start2, end1, end2;
    int x=1,i;

    start1=clock();
    for(i=0;i<LOOPS;i++)
    {
        if (x==0)
        {
            x=1;
        }
    }
    end1=clock();

    start2=clock();
    for(i=0;i<LOOPS;i++)
    {
        if (0==x)
        {
            x=1;
        }
    }
    end2=clock();

    printf("x==0 %d ns\n", end1-start1);
    printf("0==x %d ns\n", end2-start2);
}

2
对于这样微不足道的更改,最好还是查看汇编代码。(除非性能差异真的很大,否则时间差异只会是噪音。) - GManNickG
你的“基准测试”优化掉了那些条件,实际上还优化掉了 x,因为它在任何可见的输出/副作用中都没有被使用。同时,循环本身也被优化掉了。https://godbolt.org/z/8hcPMocG8。像 GManNickG 所说的那样,查看汇编代码以验证编译器是否不好并且对于源代码的任何一种编写方式都生成相同的汇编代码,在某些感兴趣的情况下。(不,禁用优化不会使这成为有用的基准测试。评估性能的惯用方式? - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接