三元运算符?:vs if…else


79

在C ++中,?:运算符是否比if()... else语句快?它们在编译后的代码之间有什么区别吗?


困难的问题,因为这也取决于编译器的优化设置。
Extraneon 2010年

3
那当然取决于您在分支机构内部的工作。条件运算符仅允许表达式,而if允许语句。
Gumbo,2010年


8
一些人随机决定编辑我这个完全可以的三年老问题,重写这个问题,使它听起来完全不像我,并添加了一些完全不必要的代码,使整个问题变得毫无意义,因为由于不断折叠,这两个样本都简化为简单的“结果” = 5英寸。正在还原。
Xirdus

Answers:


87

取决于您的编译器,但是取决于任何现代编译器,通常没有什么区别。这是您不应该担心的事情。专心于代码的可维护性。


1
+1对于许多应用程序,即使在真正的转储编译器上,性能差异也不值得考虑。

3
关于代码的可维护性,我希望在其他情况下使用。至少对我来说,它更容易阅读。
Exa 2010年

2
@Exa:取决于上下文。初始化对象时,三元运算符通常更好。
Nemanja Trifunovic

@Nemanja:这就是为什么我说“至少对我来说”。我只是提到代码的可读性:)
了Exa

1
@kotlinski,我并不是说有条件的维护要比if少。如上面链接的“三元”或“非三元”问题的答案所述,它们在某些特定情况下都更加清晰。
ptomato

107

它并不快。当您可以根据某些表达式初始化常量变量时​​,有一个区别:

const int x = (a<b) ? b : a;

您无法使用进行相同操作if-else


20
@Developer Art:使用const变量是不可能的。
工作

1
您可以创建一个非常量变量,在if / else中分配给它,然后创建一个新的const变量并使用非常量构造它。相当浪费,但绝非不可能。
小狗

1
我说那很浪费。您仅给出了一种浪费方式的示例。但这绝对不是不可能的。
小狗

7
max好吗? const int x = max(a,b);效果很好。
bobobobo 2012年

3
@bobobobo哈!当我阅读您的评论时,我以为您建议的命令是,max ? const int x = max(a,b);并以为哇!WTF就是这样!然后我又读了一遍,发现问号不是等宽的!给定主题,我认为我有理由考虑?是命令的一部分!:)
露水2014年

43

我已经看到了GCC将条件运算符转换为cmov(条件移动)指令,而将if语句转换为分支,这意味着在我们的情况下,使用条件运算符时代码会更快。但这是几年前的事,而今天最有可能的是,两者都将编译为相同的代码。

不能保证它们将编译为相同的代码。如果您需要性能,请像往常一样测量。并且,当您测量并发现1.您的代码太慢时,以及2.正是这部分特殊代码才是罪魁祸首,然后研究编译器生成的汇编代码并自己检查发生了什么。

不要相信“如果我使用条件运算符,编译器将始终生成更高效的代码”之类的黄金规则。


2
+1。当我使用GCC为PS3开发时,使用条件语句代替“ if”对避免分支很有用。
约翰·科特林斯基

这是特定于C语言的吗?c ++标准说,Only one of the second and third expressions is evaluated. Every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second or third expression.这显然阻止了编译器生成cmove指令。
zoujyjs

2
@zoujyjs不,C有相同的规则。但是,在最终规则下,只要最终结果正确,编译器就可以自由作弊。因此,只要没有副作用,编译器就可以进行此优化。
2015年

如果用cmov怎么实现?mov等于1 + cmov等于2?
西罗Santilli郝海东冠状病六四事件法轮功

1
注意:此建议已过时(cira 2010),我无法在gcc 4.4或更高版本上重现此建议。
非周期性

15

它们是相同的,但是,三元运算符可以在难以使用if / else的地方使用:

printf("Total: %d item%s", cnt, cnt != 1 ? "s" : "");

用if / else执行该语句将生成完全不同的编译代码。


8年后更新...

实际上,我认为这样会更好:

printf(cnt == 1 ? "Total: %d item" : "Total: %d items", cnt);

(实际上,我很确定您可以将第一个字符串中的“%d”替换为“一个”)


8
甚至不需要三元运算符:printf("Total: %d item%s", cnt, "s" + (cnt==1));
MSalters 2010年

@MSalters,但在字符串末尾给出一个双null,这在其他情况下可能会出现问题,其中双null表示某些东西(例如,在OPENFILENAME结构的lpStrFilter成员中)
bobobobo 2012年

1
@bobobobo:编号%s最多可打印,但不包括\0源字符串中的。
MSalters

@MSalters这是如何printf("Total: %d item%s", cnt, "s" + (cnt==1));工作的?
2015年

2
@Quirk:(cnt==1)为true或false,将其转换为0或1。“ s”是指向以nul结尾的字符串的指针。加一会跳过一个字符(即s)。因此,这将打印“ s”或“”。
MSalters 2015年


3

不管编译的代码如何,它们在语义上都是不同的。<cond>?<true expr>:<false expr>是一个表达式,if..else..是一个语句。

尽管条件表达式的语法看起来很尴尬,但这是一件好事。您被迫提供a,<false expr>并且对两个表达式进行类型检查。

if..else..Haskell与基于表达式的功能语言(如Lisp)等效,是? :用C ++而不是if..else..语句。


2

您不必被迫将所有内容放在一起:

x = y==1 ?
    2
    :// else
    3;

它比if / else清晰得多,因为您可以立即看到两个分支都导致将x分配给了x。


您也可以初始化const
QuentinUK '19

0

我希望在大多数编译器和目标平台上,有时“ if”更快,而?:更快。在某些情况下,一种形式比另一种形式更紧凑。哪种情况偏爱一种形式,另一种情况偏爱编译器和平台。如果要在嵌入式微型计算机上编写对性能至关重要的代码,请查看编译器在每种情况下生成的内容,然后看看哪种更好。在“主流” PC上,由于缓存问题,查看哪种更好的唯一方法是在类似于真实应用程序的基准中对这两种形式进行基准测试。


0

在CA三元运算符中,“?:”可用于构造形式的条件表达式

exp1 ? exp2:exp3

其中exp1,exp2和exp3是表达式

例如

        a=20;
        b=25;
        x=(a>b)?a:b;

        in the above example x value will be assigned to b;

可以使用if..else语句编写,如下所示

            if (a>b)
             x=a;
             else
             x=b;

**因此,两者之间没有区别。这对于程序员来说很容易编写,但是对于编译器来说都是相同的。*


0

在反转一些代码(几年前我不记得了)的过程中,我发现机器代码之间的单行差异是:?还有if-else。 Don't remember much but it is clear that implementation of both is different.

但我建议您不要选择其中之一来提高效率,而是根据代码的可读性或方便性来选择。快乐编码


区别在于其中一个正在使用goto进行分支,而另一个正在使用saome本机指令,我不记得哪个正在使用哪一个。.–
Pervez Alam

0

三元运算符始终返回一个值。因此,在需要从结果中获得一些输出值并且只有两个条件的情况下,最好使用三元运算符。如果上述任何条件都不成立,请使用if-else。


6
这到底是什么?你知道你在说什么吗?
2012年

0

我认为在某些情况下,内联if可以由于其作用范围而产生“更快”的代码。创建和销毁对象的成本很高,因此请考虑以下情形:

class A{
    public:
    A() : value(0) {
        cout << "Default ctor" << endl;
    }
    A(int myInt) : value(myInt)
    {
        cout << "Overloaded ctor" << endl;
    }

    A& operator=(const A& other){
        cout << "= operator" << endl;
        value = other.value; 
    }

    ~A(){
        cout << "destroyed" << std::endl;
    }

    int value;

};


int main()
{
   {
       A a;
       if(true){
           a = A(5);
       }else{
           a = A(10);
       }
   }

   cout << "Next test" << endl;
   {
        A b = true? A(5) : A(10);
   }
   return 0;
}

使用此代码,输出将是:

Default ctor                                                                                                                                                                                                                      
Overloaded ctor                                                                                                                                                                                                                   
= operator                                                                                                                                                                                                                        
destroyed                                                                                                                                                                                                                         
destroyed                                                                                                                                                                                                                         
Next test                                                                                                                                                                                                                         
Overloaded ctor                                                                                                                                                                                                                   
destroyed  

因此,通过内联if,我们节省了大量操作,以保持a与相同的作用域b。尽管两种情况下的条件评估速度极有可能相等,但是更改范围会迫使您考虑其他因素,因为如果inline允许您避免使用这种因素。


那又如何A a(true ? 5 : 10);
Quest

-1

现在,我无法为您提供帮助,也许可以解决下面的第二个问题,我想使用它吗?如果您只想了解速度,请忽略我的评论。

我只能说请谨慎使用三元组?:运算符。与可读性的诅咒一样,这可能是一种祝福。

在使用它之前先问问自己是否觉得这更容易阅读

int x = x == 1 ? x = 1 : x = 1;

if (x == 1)
{
   x = 1
}
else
{
   x = 2
}

if (x == 1)
    x = 1
else
    x = 1

是的,使代码100%伪造看起来很愚蠢。但是这个小技巧帮助我分析了代码的可读性。这是您在此样本中看到的操作员的可读性,而不是内容的可读性。

它看起来很干净,但普通的马桶座圈和门把手也很干净

根据我的经验,这是有限的,我看到很少有人能够快速引渡三元运算符所需的信息,除非100%确信会更好,否则请避免。我认为,当它也被bug修复时,这很痛苦


5
第一行可能应该阅读int x = x == 1 ? 1 : 2或可能int x = (x == 1) ? 1 : 2
Hasturkun 2010年

我的观点只是为了显示代码视图,一行的简洁性是不错的。但是,如果您想查看条件/分配,则代码的内容可能是虚假的。如果您想发现什么,您将只看操作员和位置。我看到单词IF和()我知道啊,这是一个条件。我看到A = B吗?条件:您是否立即为自己发现了条件?我知道该程序的大多数人都不知道,也许是因为我知道该程序的大多数人都是像我这样的新秀。您对数字无稽之谈是正确的,这就是重点。
Proclyon

2
第一行肯定需要一些括号。也许“ int x =(y == 1)?0:1;” 或“ int x =((y == 1)?0:1);”
supercat

6
抱歉,看到作业没有问题。如果您选择使示例过于复杂来说明问题,那就是您的问题。为什么不x = x = 1;到处写,然后抱怨作业太复杂,应该避免。
UncleBens

-4

不,它们将转换为完全相同的可执行代码。


7
-1:在什么版本的什么编译器上,在什么平台上,用什么代码?
小狗

3
DeadMG:显然是VB6编译器!
亚历克斯·F
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.