C中的三元(条件)运算符

时间:2009-04-17 03:09:41

标签: c operators ternary-operator conditional-operator

条件运算符需要什么?在功能上它是多余的,因为它实现了if-else结构。如果条件运算符比等效的if-else赋值更有效,为什么编译器不能更有效地解释if-else?

15 个答案:

答案 0 :(得分:154)

在C中,它的实际用途是它是一个表达式而不是一个语句;也就是说,您可以将其放在声明的右侧(RHS)。所以你可以更简洁地写出某些东西。

答案 1 :(得分:82)

其他一些答案很棒。但令我感到惊讶的是,没有人提到它可以用来帮助以紧凑的方式强制执行const正确性。

这样的事情:

const int n = (x != 0) ? 10 : 20;

所以基本上n const ,其初始值取决于条件语句。最简单的替代方法是使n不是const,这将允许普通的if初始化它。但是如果你希望它是const,那么普通的if无法做到这一点。你可以做的最好的替代方法是使用这样的辅助函数:

int f(int x) {
    if(x != 0) { return 10; } else { return 20; }
}

const int n = f(x);

但三元版本的版本更紧凑,可以说更具可读性。

答案 2 :(得分:62)

三元运算符是一种语法和可读性方便,而不是性能快捷方式。对于复杂程度不同的条件,人们对它的优点进行分歧,但对于短期条件,单线表达式可能很有用。

此外,因为它是一个表达式,如Charlie Martin wrote,这意味着它可以出现在C语句的右侧。这对于简洁是有价值的。

答案 3 :(得分:36)

这对代码混淆至关重要,如下所示:

Look->       See?!

No
:(
Oh, well
);

答案 4 :(得分:11)

紧凑性以及将if-then-else结构内联到表达式中的能力。

答案 5 :(得分:10)

C中有很多东西在技术上是不需要的,因为它们可以或多或少地在其他方面实现。这是一个不完整的清单:

  1. ,而
  2. 功能
  3. 结构
  4. 想象一下,如果没有这些代码,您的代码会是什么样子,您可能会找到答案。三元运算符是一种“语法糖”,如果谨慎使用,技​​巧可以使编写和理解代码更容易。

答案 6 :(得分:9)

有时,三元运算符是完成工作的最佳方式。特别是当您希望三元的结果为l值时。

这不是一个很好的例子,但我在某些方面做得更好了。有一件事是certian,当你真的需要使用三元时,它并不常见,尽管我仍然使用它很多。

const char* appTitle  = amDebugging ? "DEBUG App 1.0" : "App v 1.0";

我要警告的一件事是将三元组合在一起。他们成为真正的人 维修时间的问题:

int myVal = aIsTrue ? aVal : bIsTrue ? bVal : cIsTrue ? cVal : dVal;

编辑:这是一个可能更好的例子。您可以使用三元运算符来指定参考和& const值,否则你需要编写一个函数来处理它:

int getMyValue()
{
  if( myCondition )
    return 42;
  else
    return 314;
}

const int myValue = getMyValue();

......可能会成为:

const int myValue = myCondition ? 42 : 314;

哪个更好是一个值得商榷的问题,我会选择不进行辩论。

答案 7 :(得分:8)

由于还没有人提到这一点,关于获得智能printf语句的唯一方法是使用三元运算符:

printf("%d item%s", count, count > 1 ? "s\n" : "\n");

警告:当您从C转移到C ++时,运算符优先级存在一些差异,并且可能会因出现的细微错误而感到惊讶。

答案 8 :(得分:8)

三元运算符是表达式而不是语句的事实允许它在宏扩展中用于类似函数的宏,这些宏用作表达式的一部分。 Const可能不是原始C的一部分,但宏预处理器可以回归。

我见过它使用的一个地方是一个数组包,它使用宏来进行绑定检查的数组访问。检查引用的语法类似于aref(arrayname, type, index),其中arrayname实际上是指向包含数组边界的结构的指针和数据的unsigned char数组,type是数据的实际类型,index是指数。这种扩展非常多(我不会从内存中做到这一点),但它使用了一些三元运算符来进行绑定检查。

由于需要返回对象的多态性,因此无法在C中执行此函数调用。因此需要一个宏来在表达式中进行类型转换。 在C ++中,您可以将其作为模板化重载函数调用(可能用于operator []),但C不具备此类功能。

编辑:以下是我所谈论的例子,来自Berkeley CAD阵列包(glu 1.4版)。 array_fetch用法的文档是:

type
array_fetch(type, array, position)
typeof type;
array_t *array;
int position;
  

从数组中获取元素。一个   尝试运行时发生运行时错误   超出界限的参考   阵列。没有类型检查   在给定位置的值   实际上是使用时的类型   取消引用数组。

这里是array_fetch的宏定义(注意使用三元运算符和逗号排序运算符以正确的顺序执行所有子表达式作为单个表达式的一部分):

#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 ++向量一样增长数组)甚至比较多,涉及多个嵌套的三元运算符。

答案 9 :(得分:4)

它是语法糖,是简短的if / else块只包含一个语句的便捷简写。从功能上讲,两种结构都应该完全相同。

答案 10 :(得分:2)

三元运算符的性能可能高于普通的if else子句,这在嵌入式应用程序中可能至关重要,但编译器优化也可能会破坏这种差异。

答案 11 :(得分:1)

像dwn说的那样,性能是复杂处理器兴起的一个好处,MSDN博客Non-classical processor behavior: How doing something can be faster than not doing it给出了一个明确说明三元(条件)运算符和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;

执行时间现在独立于边界值,因为:

  

优化器能够从三元表达式中删除分支。

但在我的桌面intel i5 cpu / windows 10 / vs2015上,我的测试结果与msdn blog完全不同。

使用调试模式时,if / else cost:

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 

使用发布模式时,if / else cost:

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可能会有很大不同。

答案 12 :(得分:0)

三元= if-else的简单形式。它主要是为了便于阅读。

答案 13 :(得分:0)

  • C中一些比较模糊的运算符仅仅是因为它们允许将各种类似函数的宏实现为返回结果的单个表达式。我会说这是允许?:,运算符存在的主要目的,即使它们的功能是多余的。

    让我们说我们希望实现一个类似函数的宏,它返回两个参数中最大的一个。然后它将被称为例如:

    int x = LARGEST(1,2);
    

    将此实现为类似函数的宏的唯一方法是

    #define LARGEST(x,y) ((x) > (y) ? (x) : (y))
    

    使用if ... else语句是不可能的,因为它不返回结果值。 注)功能

  • ?:的另一个目的是它在某些情况下实际上提高了可读性。大多数情况下if...else更具可读性,但并非总是如此。以长,重复的切换语句为例:

    switch(something)
    {
      case A: 
        if(x == A)
        {
          array[i] = x;
        }
        else
        {
          array[i] = y;
        }
        break;
    
      case B: 
        if(x == B)
        {
          array[i] = x;
        }
        else
        {
          array[i] = y;
        }
        break;
      ...
    }
    

    这可以用更易读的

    代替
    switch(something)
    {
      case A: array[i] = (x == A) ? x : y; break;
      case B: array[i] = (x == B) ? x : y; break;
      ...
    }
    
  • 请注意,?: 永远不会导致代码速度超过if-else。这是由迷茫的初学者创造的一些奇怪的神话。在优化代码的情况下,?:在绝大多数情况下提供与if-else相同的性能。

    如果有的话,?:可以慢于<{em> ,因为它带有强制隐式类型促销,即使是不会被使用的操作数也是如此。但if-else永远不会比?:快。

注意)当然,有人会争辩并想知道为什么不使用一个函数。实际上,如果你可以使用一个函数,那么总是比类似函数的宏更可取。但有时你不能使用功能。例如,假设上面示例中的if-else在文件范围内声明。初始化程序必须是常量表达式,因此它不能包含函数调用。您必须使用类似函数的宏的其他实际示例涉及使用x或“X宏”进行类型安全编程。

答案 14 :(得分:-3)

相同
if(0)
do();


if(0)
{
do();
}