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

Bon*_*abu 53 c operators ternary-operator conditional-operator

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

Cha*_*tin 155

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

  • 这是重点.它将if/else转换为表达式,而不是语句.不知怎的,我怀疑这里有不少人不明白这些差异(请不要评论你做的,我不跟你说话;)). (18认同)
  • @Charlie:+1.我在我的网站上提到了这一点,但最好还是明确指出这一点. (3认同)

Eva*_*ran 82

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

像这样的东西:

const int n = (x != 0) ? 10 : 20;
Run Code Online (Sandbox Code Playgroud)

所以基本上n是一个const初始值取决于条件语句.最简单的选择是n不使用const,这将允许普通if的初始化它.但如果你想要它const,那就不能用普通的方式来完成if.你可以做的最好的替代方法是使用这样的辅助函数:

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

const int n = f(x);
Run Code Online (Sandbox Code Playgroud)

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

  • 好吧,const*确实*在条件运算符之后25年左右出现了.这是一个可爱的伎俩. (4认同)

Joh*_*lla 63

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

此外,正如查理·马丁所写,这是一个表达,这意味着它可以出现在C语句的右侧.这对于简洁是有价值的.

  • 性能是复杂处理器兴起期间的优势之一.您不必转储整个处理器管道以获取分支,然后可能执行额外的副本,而是通常只需将一个就绪值推入管道.此外,对于多行表达式而言,它通常比"if(A)return ret1; 否则,如果(B)返回ret2; ......".没有什么难以阅读...返回A?ret0:B?ret1:C?ret2:D?ret3; (5认同)

Art*_*ius 38

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

Look->       See?!

No
:(
Oh, well
);
Run Code Online (Sandbox Code Playgroud)

  • 注意:要使上面的代码编译,只需添加struct {int See;}*Look; int No,哦,好吧; int main(){/*上面代码进入这里*/} (5认同)

tva*_*son 11

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


180*_*ION 11

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

  1. 对于
  2. 功能
  3. 结构

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

  • 为了继续论证,我们根本不需要C,因为我们可以使用汇编程序完成所有必要的工作. (4认同)

Joh*_*ing 9

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

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

const char* appTitle  = amDebugging ? "DEBUG App 1.0" : "App v 1.0";
Run Code Online (Sandbox Code Playgroud)

我要警告的一件事是将三元组串在一起.它们
在维护时成为一个真正的问题:

int myVal = aIsTrue ? aVal : bIsTrue ? bVal : cIsTrue ? cVal : dVal;
Run Code Online (Sandbox Code Playgroud)

编辑:这是一个可能更好的例子.您可以使用三元运算符来分配引用和const值,否则您需要编写一个函数来处理它:

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

const int myValue = getMyValue();
Run Code Online (Sandbox Code Playgroud)

......可能成为:

const int myValue = myCondition ? 42 : 314;
Run Code Online (Sandbox Code Playgroud)

哪个更好是一个有争议的问题,我会选择不讨论.


dir*_*tly 8

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

printf("%d item%s", count, count > 1 ? "s\n" : "\n");
Run Code Online (Sandbox Code Playgroud)

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


dew*_*ell 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;
Run Code Online (Sandbox Code Playgroud)

从数组中获取元素.尝试在数组边界外引用时发生运行时错误.没有类型检查,给定位置的值实际上是取消引用数组时使用的类型.

这里是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)))
Run Code Online (Sandbox Code Playgroud)

array_insert的扩展(如果需要,它会像C++向量一样增长数组)甚至比较多,涉及多个嵌套的三元运算符.