C中的三元(条件)运算符
什么是条件运算符的需要? 在function上它是多余的,因为它实现了一个if-else结构。 如果条件运算符比等价的if-else赋值更有效,为什么if-else不能被编译器更有效地解释呢?
三元运算符是一个句法和可读性的便利,而不是性能捷径。 对于复杂度不同的条件,人们被分成了不同的条件,但在短期条件下,有一条单行expression是有用的。
而且,正如查理·马丁(Charlie Martin)所写的那样,这是一种expression方式,这意味着它可以出现在C语句的右边。这对简明而言是有价值的。
在C中,它的实际效用是它是一个expression式而不是一个声明; 也就是说,你可以把它放在陈述的右边(RHS)。 所以你可以写一些更简洁的东西。
其他一些答案很好。 但是我很惊讶,没有人提到它可以用来以紧凑的方式强制const
正确性。
像这样的东西:
const int n = (x != 0) ? 10 : 20;
所以基本上n
是一个const
它的初始值依赖于一个条件语句。 最简单的select是让n
不是一个const
,这将允许一个普通的if
初始化它。 但是如果你想让它成为const
,那么用普通的if
就不行。 你可以做的最好的替代品是使用这样的帮手function:
int f(int x) { if(x != 0) { return 10; } else { return 20; } } const int n = f(x);
但是三元版本更加紧凑,可读性更高。
代码混淆是至关重要的,如下所示:
Look-> See?! No :( Oh, well );
紧凑性以及将if-then-else构造内联到expression式中的能力。
C中有很多东西不是技术上需要的,因为它们可以或多或less地用其他方式实现。 这是一个不完整的列表:
- 而
- 对于
- function
- 结构
想象一下,如果没有这些代码,你的代码会是什么样的,你可能会find你的答案。 三元运算符是一种“语法糖”的forms,如果谨慎使用,使得编写和理解代码更容易。
有时三元操作员是完成工作的最好方法。 特别是当你想要三元的结果是一个l值。
这不是一个很好的例子,但我更好地在一些事情上画空白。 有一点是可靠的,当你真的需要使用这个三元组的时候并不常见,尽pipe我仍然使用它。
const char* appTitle = amDebugging ? "DEBUG App 1.0" : "App v 1.0";
有一件事我会警告,虽然是串起三元组在一起。 他们成为一个真实的
维护时间问题:
int myVal = aIsTrue ? aVal : bIsTrue ? bVal : cIsTrue ? cVal : dVal;
编辑 :这是一个潜在的更好的例子。 您可以使用三元运算符来分配引用和常量值,否则您需要编写一个函数来处理它:
int getMyValue() { if( myCondition ) return 42; else return 314; } const int myValue = getMyValue();
…可能成为:
const int myValue = myCondition ? 42 : 314;
哪一个更好是一个值得商榷的问题,我会select不去辩论。
三元运算符是一个expression式,而不是一个语句,这个事实允许它在用于expression式的函数式macros的macros扩展中使用。 Const可能不是原来的C的一部分,但是macros预处理器可以返回。
我已经看到它使用的一个地方是在使用macros进行绑定检查的数组访问的数组包中。 检查引用的语法类似于aref(arrayname, type, index)
,其中arrayname实际上是指向包含数组边界的结构的指针和数据的unsigned char数组,type是数据的实际types,指数是指数。 这个扩展非常多(我不打算从内存中去做),但是它使用了一些三元运算符来进行绑定检查。
你不能在C中做一个函数调用,因为需要返回对象的多态性。 所以需要一个macros在expression式中进行types转换。 在C ++中,您可以将其作为模板化的重载函数调用(可能用于运算符[]),但是C没有这种function。
编辑:这是我正在谈论的例子,从伯克利CAD数组包(glu 1.4版)。 array_fetch用法的文档是:
type array_fetch(type, array, position) typeof type; array_t *array; int position;
从数组中获取元素。 试图在数组边界外引用时发生运行时错误。 没有types检查,给定位置的值实际上是解引用数组时使用的types。
这里是array_fetch的macros定义(注意使用三元运算符和逗号sorting运算符,以正确的顺序执行所有的子expression式,作为单个expression式的一部分):
#define array_fetch(type, a, i) \ (array_global_index = (i), \ (array_global_index >= (a)->num) ? array_abort((a),1) : 0,\ *((type *) ((a)->space + array_global_index * (a)->obj_size)))
array_insert的扩展(如果需要的话,像C ++向量那样增长数组)更加多,涉及多个嵌套的三元运算符。
由于没有人提到过这一点,所以获得智能printf
语句的唯一方法是使用三元运算符:
printf("%d item%s", count, count > 1 ? "s\n" : "\n");
警告:当你从C移到C ++时,在运算符优先级上有一些差异,并且可能会由于它产生的微妙的错误而感到惊讶。
它是Syntally糖,简单的if / else块只包含一个语句。 在function上,两个结构应该相同地执行。
三元运算符可能比正常的if else子句性能更好,这可能在embedded式应用程序中至关重要,而且编译器优化可能会破坏这种差异。
在一些编程语言中,if-else是一个expression式并且计算为一个值
def correct = true; def answer = if (correct) "Yes" else "No";
所以不需要一个条件expression式。
三元= if-else的简单forms。 它主要用于可读性。
像dwn说的那样,性能是它在复杂处理器崛起过程中的一个好处,MSDN博客非经典处理器行为:如何做某事可能比不做这件事情快得多 ,这个例子清楚地表明了三元(条件)算子和if / else语句。
给出以下代码:
#include <windows.h> #include <stdlib.h> #include <stdlib.h> #include <stdio.h> int array[10000]; int countthem(int boundary) { int count = 0; for (int i = 0; i < 10000; i++) { if (array[i] < boundary) count++; } return count; } int __cdecl wmain(int, wchar_t **) { for (int i = 0; i < 10000; i++) array[i] = rand() % 10; for (int boundary = 0; boundary <= 10; boundary++) { LARGE_INTEGER liStart, liEnd; QueryPerformanceCounter(&liStart); int count = 0; for (int iterations = 0; iterations < 100; iterations++) { count += countthem(boundary); } QueryPerformanceCounter(&liEnd); printf("count=%7d, time = %I64d\n", count, liEnd.QuadPart - liStart.QuadPart); } return 0; }
不同边界的成本差别很大(见原始资料)。 而如果改变:
if (array[i] < boundary) count++;
至
count += (array[i] < boundary) ? 1 : 0;
执行时间现在独立于边界值,因为:
优化器能够从三元expression式中移除分支。
但在我的台式机上intel i5 cpu / windows 10 / vs2015,我的testing结果跟msdn博客有很大的不同。
当使用debugging模式时 ,if / else的成本:
count= 0, time = 6434 count= 100000, time = 7652 count= 200800, time = 10124 count= 300200, time = 12820 count= 403100, time = 15566 count= 497400, time = 16911 count= 602900, time = 15999 count= 700700, time = 12997 count= 797500, time = 11465 count= 902500, time = 7619 count=1000000, time = 6429
和三元运营商成本:
count= 0, time = 7045 count= 100000, time = 10194 count= 200800, time = 12080 count= 300200, time = 15007 count= 403100, time = 18519 count= 497400, time = 20957 count= 602900, time = 17851 count= 700700, time = 14593 count= 797500, time = 12390 count= 902500, time = 9283 count=1000000, time = 7020
当使用释放模式时 ,如果/ else成本:
count= 0, time = 7 count= 100000, time = 9 count= 200800, time = 9 count= 300200, time = 9 count= 403100, time = 9 count= 497400, time = 8 count= 602900, time = 7 count= 700700, time = 7 count= 797500, time = 10 count= 902500, time = 7 count=1000000, time = 7
和三元运营商成本:
count= 0, time = 16 count= 100000, time = 17 count= 200800, time = 18 count= 300200, time = 16 count= 403100, time = 22 count= 497400, time = 16 count= 602900, time = 16 count= 700700, time = 15 count= 797500, time = 15 count= 902500, time = 16 count=1000000, time = 16
三元运算符比我的机器上的if / else语句慢!
所以根据不同的编译器优化技术,ternal运算符和if / else可能会有很大的不同。
和…一样
if(0) do(); if(0) { do(); }