6

GCC对 C 有一个很棒的三元表达式扩展,它允许我们创建这样的语句:

int x = some_var ?: 10; // expands to some_var ? some_var : 10

这真的很好,虽然它不是特别直观,但它确实有效。C 语言中的大多数二元运算符都有一个与之关联的附加运算符,它允许赋值:

x = x + 2;

// instead, we can say
x += 2;

既然是这种情况,并且是大多数二元 C 运算符(+, -, *, /, %, |, &, ^)的规范,为什么三元扩展运算符不是这种情况:

int x = ...;
x ?:= 2; // error: Expected expression before '=' token

// which would expand to
x = x ?: 2;

标准 C 中唯一支持这一点的运算符是逻辑运算符 ( ||, &&),绝对三元不属于这些运算符,那么为什么我们不能这样做呢?

我真的很想在我的代码中做一个带有酷发型的笑脸,但我做不到!这是设计操作员时的疏忽,还是故意并记录在某处?这是运算符短路其操作数的结果,还是完全其他原因?

4

1 回答 1

8

要回答这个问题,我相信还有一些其他的问题需要回答。

为什么 C 语言中有一个?:运算符,为什么它比if-else?

据我所知,没有人能够回答这个问题,而不仅仅是陈述自己的主观意见。K&R 2.11 指出

“条件表达式通常会导致代码简洁。”

然后他们用这条线来说明这一点

printf("%6d%c", a[i], (i%10==9 || i==n-1) ? '\n' : ' ');

这是他们自己主观的、模糊的意见。就个人而言,我相信

printf("%6d", a[i]);

if(i%10==9 || i==n-1)
  printf("\n");
else
  printf(" ");

更清晰,因为我可以在 10 秒内阅读和理解该代码,而不是 1 分钟阅读和理解 K&R 版本。此外,我的代码将整数打印与不相关的格式分开。但当然,这是我的主观意见,没有明显的对错。

至于官方消息,C99 基本原理版本 5.10、6.5.15 并没有真正提到为什么需要 ?: 运算符。它主要只是说明操作员的行为在新标准中有所改变:

对条件运算符的中间操作数的句法限制已经放宽,不仅包括逻辑或表达式:一些现存的实现已经采用了这种做法。

条件运算符表达式的类型可以是 void、结构或联合;大多数其他运算符不处理此类类型。然而,在指针和整数之间平衡类型的规则已经收紧,因为现在只有常量 0 可以可移植地强制转换为指针。

因此,如果有人想对 struct 或 union 类型执行算术运算,那么 ?: 应该比 if-else 更方便。我认为这没有明显的好处,但至少它是运营商存在的一些理由。

下一个问题将是:

为什么?:GCC 编译器中的操作数有编译器扩展?

这里提到了这个问题的答案:

当它变得有用时,第一个操作数确实或可能(如果它是宏参数)包含副作用。然后在中间重复操作数将执行两次副作用。省略中间操作数会使用已经计算的值,而不会产生重新计算的不良影响。

所以这个 GCC 扩展与可读性或语言一致性无关,它只是为了避免不必要的副作用而添加的。

然后尝试回答原始问题:

为什么GCC的三元扩展不支持赋值?

可能是因为在赋值条件中访问左值通常不会产生任何不需要的副作用。x = x ? : 2;如果将 x 声明为 a,则只会产生不需要的副作用volatile- 读取 volatile 变量是一种副作用。所以我能看到的唯一实际用途x ?:= 2;是防止某人在同一个条件表达式中访问同一个 volatile 变量两次。

这是一个非常狭窄且价值有限的特征。在某些特殊的嵌入式系统案例中,它可能会很有用,您可以在要求苛刻的实时系统中读取硬件寄存器……除此之外,我认为它没有任何用处。

除了传统和主观编码风格偏好之外,我也找不到任何官方或规范来源说明 ?: 运算符本身的任何用途。

于 2013-06-04T20:12:33.737 回答