三元运算符的性能成本是多少?

3
我听说编译器非常聪明,知道如何优化if / else语句。
我也听说三元运算符具有高性能,因为它们通过CPU的指令流水线较少。
让我澄清一下,基于我所听到的:
if / else必须将其条件通过管道传递并等待结果,然后才能执行结果的计算。
然而,三元运算符可以将两个结果的计算都传递给CPU,而无需等待布尔表达式通过管道。
那么,哪个更快,三元运算符还是if / else?

这取决于编译器。一些天真的、非优化的编译器可能会使用条件移动来处理三元运算符,并使用分支语句处理if/else语句,但在更复杂的编译器的SSA转换阶段,两者之间的任何区别都会被消除。 - Iwillnotexist Idonotexist
1
至少在C语言中,?:的语义禁止评估未选择的一侧,就像if() else一样。编译器只有在遵守as-if规则的情况下才能评估两个执行路径,即编译器可以证明额外的计算不会产生任何可观察的副作用。同样,这对于?:if() else都是完全相同的情况。 - cmaster - reinstate monica
一个天真的、非优化的编译器无法证明它可以评估两个路径。因此,它必须在没有条件移动的情况下编译?:。只有聪明的编译器才能证明这样的事情,并在这里使用条件移动。 - cmaster - reinstate monica
@cmaster 确实如此;但我考虑的是简单的 d = c ? a : b 示例,其中 ab 不会产生副作用。否则需要完整的 if/else - Iwillnotexist Idonotexist
1
@我不会存在我不存在 这些“琐碎”的例子可以通过移动编译。但是:分支代码可以表示所有?:的实例,而条件移动代码则不能。因此,一个天真的、非优化的编译器将始终选择将所有?:的实例编译成分支代码,避免决定是否有更好的选择。 - cmaster - reinstate monica
1个回答

6
没有性能差异,三元运算符只是一种语法糖。
来自ISO / IEC 9899 C标准(draft,第90页):
6.5.15条件运算符
(...)
语义
评估第一个操作数; 它的评估后有一个序列点。仅当第一个操作数与0不相等时,才评估第二个操作数; 仅当第一个操作数与0相等时,才评估第三个操作数; 结果是第二个或第三个操作数的值(评估哪个),转换为下面描述的类型。 (...)

3
只是为了支持您的答案: https://dev59.com/83A65IYBdhLWcg3w6DJO - azngunit81
从其他答案所说的来看,只有在编译器设置为特定的优化级别时它们才是相同的。 - Magical Gordon
2
@MagicalGordon 他们是相同的;唯一的区别是一个(if(c){a}else{b})是语句,而另一个(c ? a : b)是表达式。C标准草案正好描述了?:的机制就像一个if/else:首先评估条件,然后发生一个序列点,然后评估ab但不是两者都评估。如果编译器通过_as-if_规则同时评估两个表达式具有与仅评估一个表达式相同的效果,则可以评估两个表达式;但是,如果评估任何一个表达式会导致副作用,则不能这样做。 - Iwillnotexist Idonotexist
1
这取决于你所说的“相同”的意思 - C标准规定它们具有相同的效果 - 但编译器当然可以比另一个实现更有效率!存在许多情况,两个结构具有完全相同的可观察行为,但编译器可能会以不同的方式实现它们。例如,在没有优化标志的情况下,iccclang都使用条件移动编译简单的(无副作用)三元运算符,而ifs则编译为跳转。优化改变了事情,然后它们似乎更喜欢条件移动。 - BeeOnRope
我在编译器浏览器上进行了检查,对于大多数简单用例,生成的汇编代码也完全相同。有一个情况下,我发现三元运算符具有更好的性能,即在创建一个重对象(具有非POD大内存占用)时,我们决定使用(如果条件为真,则为object1,否则为object2)进行初始化。我能想到的唯一原因是,在if / else的情况下,由于默认构造+复制赋值,而在三元运算符中仅进行复制构造。但我不太确定。 - Anirudh

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