当前位置: C语言 -- 基础 -- 表达式

表达式(十六)

十二、条件运算符

条件运算符(conditional operator)也称三元运算符,其语法格式如下所示:

condition ? expression1 : expression2

其中condition是条件表达式,是条件运算符的第一个操作数,应为标量类型(scalar type);expression1expression2分别是条件运算符的第二个操作数和第三个操作数。


条件运算符运算结果的类型与第二个操作数和第三个操作数的类型有关,第二个操作数和第三个操作数的类型应满足以下条件之一:

-- 两个操作数都具有算术类型。

int i = 1;
signed char ch = 'A';
float f = 3.14f;

i ? ch : f; //表达式的值是65.0,类型是float类型。

如果条件运算符的第二个操作数和第三个操作数都具有算术类型,这两个操作数执行常用算术转换(usual arithmetic conversions),常用算术转换确定的结果类型是条件运算符运算结果的类型。


-- 两个操作数具有兼容的结构或者联合类型。

struct s1{
  int i;
};

struct s2{
  int i;
};

struct s1 a, b;
struct s2 c;
int i = 0;
...
i ? a : b;  //合法,结果类型是struct s1类型。
i ? a : c;  //非法,表达式a和表达式c的类型不兼容。

如果条件运算符的第二个操作数和第三个操作数具有兼容的结构或者联合类型,条件运算符运算结果的类型是两个操作数类型构成的复合类型(composite type);如果两个操作数类型相同,结果类型与操作数类型相同。


-- 两个操作数都具有void类型。

int i = 0;

i ? (void)printf("%d\n", 0) : (void)printf("%d\n", 1);	//结果类型是void类型。

如果条件运算符的第二个操作数和第三个操作数都具有void类型,条件运算符的运算结果具有void类型。


-- 两个操作数都是指向限定或者非限定版本的兼容类型的指针。

int i = 0;
int a, b;
volatile int *p1 = &a;
const int *p2 = &b;

i ? p1 : p2;	//结果类型是volatile const int *类型。

如果条件运算符的第二个操作数和第三个操作数都是指向限定或者非限定版本的兼容类型的指针,条件运算符的运算结果类型为指针类型,该类型指针指向对象具有两个操作数指向对象的所有类型限定符。


-- 两个操作数都具有nullptr_t类型。

nullptr_t p1, p2;
int i = 0;

i ? p1 : p2;  //结果类型是nullptr_t类型。

如果条件运算符的第二个操作数和第三个操作数都具有nullptr_t类型,条件运算符的运算结果具有nullptr_t类型。


-- 一个操作数是指针类型,另一个操作数是空指针常量(null pointer constant)或者具有nullptr_t类型。

int i = 0;
int a;
const int *ptr = &a;

i ? ptr : NULL;	//结果类型是const int *类型。

如果条件运算符的第二个操作数和第三个操作数一个操作数是指针,另一个操作数是空指针常量(指针除外)或者具有nullptr_t类型,条件运算符的运算结果类型是指针类型。


-- 一个操作数是指向对象类型的指针,另一个操作数是指向限定或者非限定版本的void类型的指针。

int i = 1;
int a, b;
volatile int *p1 = &a;
const void *p2 = (void *)&b;

i ? p1 : p2;	//结果类型是volatile const void *类型。

如果条件运算符的第二个操作数和第三个操作数中一个操作数是指向对象类型的指针,另一个操作数是指向限定或者非限定版本的void类型的指针,条件运算符的运算结果为指向void类型的指针,该指针指向对象具有两个操作数指向对象的所有类型限定符。


如果条件运算符的第二个操作数和第三个操作数中一个操作数是指向可变修改类型(variably modified type)的指针,另一个操作数是空指针常量或者具有nullptr_t类型,如果可变修改类型依赖的数组大小表达式未被评估,则行为是未定义的。

int i = 1;
int n;
int (*ptr)[n];

i ? ptr : NULL; //未定义行为,数组大小未知。

n = 3;
i ? ptr : NULL; //合法,数组大小已知。

如果条件运算符的第二个操作数和第三个操作数中一个是十进制浮点类型(decimal floating type),另一个不能是标准浮点类型(standard floating type)、复数类型或者虚数类型。

// 以下条件表达式非法;
// 1.23DD是_Decimal64类型,属于十进制浮点类型;
// 3.14是double类型,属于标准浮点类型。
int i = 1;
i ? 1.23DD : 3.14;	//非法

条件运算符第一个操作数的评估与第二个操作数(或者第三个操作数)的评估之间存在一个序列点(sequence point),即先评估第一个操作数,再评估第二个操作数(或者第三个操作数)。仅当第一个操作数不等于0时,才评估第二个操作数;仅当第一个操作数等于0时,才评估第三个操作数。

int i = 0;
int a = 0;
int b = 0;

i ? a++ : b++;
printf("%d\n", a);  //输出0。
printf("%d\n", b);  //输出1。

条件表达式不会生成左值;条件运算符运算结果值是第二个操作数或者第三个操作数的值(以被评估操作数的值为准。)。

int i = 0;
int a = 3;
int b = 8;

printf("%d\n", !i ? a++ : b++);  //输出3。