C 中的三元(条件)运算符
什么情况下需要条件运算符? 从功能上讲,它是多余的,因为它实现了 if-else 结构。 如果条件运算符比等效的 if-else 赋值更有效,为什么编译器不能更有效地解释 if-else?
What is the need for the conditional operator? Functionally it is redundant, since it implements an if-else construct. If the conditional operator is more efficient than the equivalent if-else assignment, why can't if-else be interpreted more efficiently by the compiler?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
在 C 语言中,它的真正用途在于它是一个表达式,而不是一个语句; 也就是说,您可以将其放在语句的右侧 (RHS)。 这样你就可以把某些东西写得更简洁。
In C, the real utility of it is that it's an expression instead of a statement; that is, you can have it on the right-hand side (RHS) of a statement. So you can write certain things more concisely.
给出的其他一些答案很棒。 但令我惊讶的是,没有人提到它可以用来以一种紧凑的方式帮助强制 const 正确性。
像这样:
所以基本上
n
是一个const
,其初始值取决于条件语句。 最简单的替代方法是使n
不是const
,这将允许普通的if
对其进行初始化。 但如果你希望它是const,就不能用普通的if来完成。 您可以做的最好的替代方法是使用这样的辅助函数:但是三元 if 版本更加紧凑,并且可以说更具可读性。
Some of the other answers given are great. But I am surprised that no one mentioned that it can be used to help enforce
const
correctness in a compact way.Something like this:
so basically
n
is aconst
whose initial value is dependent on a condition statement. The easiest alternative is to maken
not aconst
, this would allow an ordinaryif
to initialize it. But if you want it to beconst
, it cannot be done with an ordinaryif
. The best substitute you could make would be to use a helper function like this:but the ternary if version is far more compact and arguably more readable.
三元运算符是一种语法和可读性的便利,而不是性能的捷径。 对于复杂程度不同的条件,人们对其优点存在分歧,但对于较短的条件,使用一行表达式可能会很有用。
此外,由于它是一个表达式,正如 Charlie Martin 所写,这意味着它可以出现在语句的右侧这对于简洁来说很有价值。
The ternary operator is a syntactic and readability convenience, not a performance shortcut. People are split on the merits of it for conditionals of varying complexity, but for short conditions, it can be useful to have a one-line expression.
Moreover, since it's an expression, as Charlie Martin wrote, that means it can appear on the right-hand side of a statement in C. This is valuable for being concise.
这对于代码混淆至关重要,如下所示:
It's crucial for code obfuscation, like this:
紧凑性以及将 if-then-else 构造内联到表达式中的能力。
Compactness and the ability to inline an if-then-else construct into an expression.
C 中有很多东西在技术上并不需要,因为它们或多或少可以很容易地用其他东西来实现。 这是一个不完整的列表:
想象一下如果没有这些,您的代码会是什么样子,您可能会找到答案。 三元运算符是“语法糖”的一种形式,如果小心和熟练地使用它,可以使编写和理解代码变得更容易。
There are a lot of things in C that aren't technically needed because they can be more or less easily implemented in terms of other things. Here is an incomplete list:
Imagine what your code would look like without these and you may find your answer. The ternary operator is a form of "syntactic sugar" that if used with care and skill makes writing and understanding code easier.
有时三元运算符是完成工作的最佳方法。 特别是当您希望三元的结果为左值时。
这不是一个很好的例子,但我在更好的事情上画了一个空白。 有一点是确定的,当你真正需要使用三元的时候并不经常,尽管我仍然经常使用它。
我要警告的一件事是将三元串在一起。 他们成为真正的
维护时的问题:
编辑:这是一个可能更好的例子。 您可以使用三元运算符来分配引用 & const 值,否则您需要编写一个函数来处理它:
...可能会变成:
哪个更好是一个有争议的问题,我将选择不争论。
Sometimes the ternary operator is the best way to get the job done. In particular when you want the result of the ternary to be an l-value.
This is not a good example, but I'm drawing a blank on somethign better. One thing is certian, it is not often when you really need to use the ternary, although I still use it quite a bit.
One thing I would warn against though is stringing ternaries together. They become a real
problem at maintennance time:
EDIT: Here's a potentially better example. You can use the ternary operator to assign references & const values where you would otherwise need to write a function to handle it:
...could become:
Which is better is a debatable question that I will choose not to debate.
由于尚未有人提到这一点,获得智能
printf
语句的唯一方法是使用三元运算符:警告:当您从 C 迁移到 C++ 时,运算符优先级存在一些差异,并且可能会对由此产生的微妙错误感到惊讶。
Since no one has mentioned this yet, about the only way to get smart
printf
statements is to use the ternary operator:Caveat: There are some differences in operator precedence when you move from C to C++ and may be surprised by the subtle bug(s) that arise thereof.
事实上,三元运算符是一个表达式,而不是一个语句,因此可以将其用于用作表达式一部分的类函数宏的宏扩展中。 Const 可能不是原始 C 的一部分,但宏预处理器可以追溯到很久以前。
我看到它使用的一个地方是在一个数组包中,该包使用宏进行绑定检查数组访问。 检查引用的语法类似于 aref(arrayname, type, index),其中 arrayname 实际上是指向包含数组边界和数据的无符号 char 数组的结构的指针,类型为数据的实际类型,index是索引。 这个扩展非常麻烦(我不会凭记忆来做),但它使用了一些三元运算符来进行边界检查。
由于需要返回对象的多态性,因此不能将其作为 C 中的函数调用来执行。 因此需要一个宏来在表达式中进行类型转换。
在 C++ 中,您可以将其作为模板化重载函数调用(可能用于运算符 [])来执行此操作,但 C 没有此类功能。
编辑:这是我正在谈论的示例,来自 Berkeley CAD 数组包(glu 1.4 版)。 array_fetch 用法的文档是:
这里是 array_fetch 的宏定义(注意使用三元运算符和逗号排序运算符作为单个表达式的一部分以正确的顺序执行具有正确值的所有子表达式):
array_insert 的扩展(它增加了数组(如果需要的话,就像 C++ 向量)甚至更加毛茸茸的,涉及多个嵌套的三元运算符。
The fact that the ternary operator is an expression, not a statement, allows it to be used in macro expansions for function-like macros that are used as part of an expression. Const may not have been part of original C, but the macro pre-processor goes way back.
One place where I've seen it used is in an array package that used macros for bound-checked array accesses. The syntax for a checked reference was something like
aref(arrayname, type, index)
, where arrayname was actually a pointer to a struct that included the array bounds and an unsigned char array for the data, type was the actual type of the data, and index was the index. The expansion of this was quite hairy (and I'm not going to do it from memory), but it used some ternary operators to do the bound checking.You can't do this as a function call in C because of the need for polymorphism of the returned object. So a macro was needed to do the type casting in the expression.
In C++ you could do this as a templated overloaded function call (probably for operator[]), but C doesn't have such features.
Edit: Here's the example I was talking about, from the Berkeley CAD array package (glu 1.4 edition). The documentation of the array_fetch usage is:
and here is the macro defintion of array_fetch (note the use of the ternary operator and the comma sequencing operator to execute all the subexpressions with the right values in the right order as part of a single expression):
The expansion for array_insert ( which grows the array if necessary, like a C++ vector) is even hairier, involving multiple nested ternary operators.
它是语法糖,是仅包含一个语句的简短 if/else 块的方便简写。 从功能上讲,两种构造的性能应该相同。
It's syntatic sugar and a handy shorthand for brief if/else blocks that only contain one statement. Functionally, both constructs should perform identically.
正如 dwn 所说,在复杂处理器兴起期间,性能是其优势之一,MSDN 博客 非经典处理器行为:做某事如何比不做它更快给出了一个例子,清楚地说明了三元(条件)运算符和 if/else 语句之间的区别。
给出以下代码:
不同边界的成本有很大不同且很奇怪(请参阅原始材料)。 while if change:
to
执行时间现在与边界值无关,因为:
但在我的台式机intel i5 cpu/windows 10/vs2015上,我的测试结果与msdn博客有很大不同。
使用调试模式时,if/else 成本:
和三元运算符成本:
使用发布模式时,if/else 成本:
和三元运算符成本:
三元运算符慢于我的机器上的 if/else 语句!
因此,根据不同的编译器优化技术,三元运算符和 if/else 的行为可能有很大不同。
like dwn said, Performance was one of its benefits during the rise of complex processors, MSDN blog Non-classical processor behavior: How doing something can be faster than not doing it gives an example which clearly says the difference between ternary (conditional) operator and if/else statement.
give the following code:
the cost for different boundary are much different and wierd (see the original material). while if change:
to
The execution time is now independent of the boundary value, since:
but on my desktop intel i5 cpu/windows 10/vs2015, my test result is quite different with msdn blog.
when using debug mode, if/else cost:
and ternary operator cost:
when using release mode, if/else cost:
and ternary operator cost:
the ternary operator is slower than if/else statement on my machine!
so according to different compiler optimization techniques, ternal operator and if/else may behaves much different.
C 中一些比较晦涩的运算符的存在仅仅是因为它们允许将各种类似函数的宏实现为返回结果的单个表达式。 我想说,这是允许
?:
和,
运算符存在的主要目的,即使它们的功能在其他方面是多余的。假设我们希望实现一个类似函数的宏,它返回两个参数中最大的一个。 然后它将被调用,例如:
将其实现为类似函数的宏的唯一方法是
使用
if ... else
语句是不可能的,因为它不返回结果值。 注意)?:
的另一个目的是它在某些情况下实际上提高了可读性。 大多数情况下,if...else
更具可读性,但并非总是如此。 以长的、重复的 switch 语句为例:这可以替换为更具可读性的
请注意
?:
不会产生比更快的代码if-else
。 这是困惑的初学者创造的一些奇怪的神话。 在优化代码的情况下,?:
在绝大多数情况下提供与if-else
相同的性能。如果有的话,
?:
可能比if-else
慢,因为它带有强制隐式类型提升,即使是操作数不会被使用。 但是?:
永远不会比if-else
更快。注意) 现在当然有人会争论并想知道为什么不使用函数。 事实上,如果您可以使用函数,它总是优于类似函数的宏。 但有时你不能使用函数。 例如,假设上例中的
x
是在文件范围内声明的。 初始值设定项必须是常量表达式,因此它不能包含函数调用。 其他必须使用类函数宏的实际示例涉及使用_Generic
或“X 宏”进行类型安全编程。Some of the more obscure operators in C exist solely because they allow implementation of various function-like macros as a single expression that returns a result. I would say that this is the main purpose why the
?:
and,
operators are allowed to exist, even though their functionality is otherwise redundant.Lets say we wish to implement a function-like macro that returns the largest of two parameters. It would then be called as for example:
The only way to implement this as a function-like macro would be
It wouldn't be possible with an
if ... else
statement, since it does not return a result value. Note)The other purpose of
?:
is that it in some cases actually increases readability. Most oftenif...else
is more readable, but not always. Take for example long, repetitive switch statements:This can be replaced with the far more readable
Please note that
?:
does never result in faster code thanif-else
. That's some strange myth created by confused beginners. In case of optimized code,?:
gives identical performance asif-else
in the vast majority of the cases.If anything,
?:
can be slower thanif-else
, because it comes with mandatory implicit type promotions, even of the operand which is not going to be used. But?:
can never be faster thanif-else
.Note) Now of course someone will argue and wonder why not use a function. Indeed if you can use a function, it is always preferable over a function-like macro. But sometimes you can't use functions. Suppose for example that
x
in the example above is declared at file scope. The initializer must then be a constant expression, so it cannot contain a function call. Other practical examples of where you have to use function-like macros involve type safe programming with_Generic
or "X macros".三元 = if-else 的简单形式。 它主要是为了可读性而提供的。
ternary = simple form of if-else. It is available mostly for readability.
与
The same as