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

标签 c gcc ternary-operator gcc-extensions

GCC 有一个 awesome ternary expression extension to 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 中唯一支持的运算符是逻辑运算符(||&&),这绝对是三元不属于,那我们为什么不能这样做呢?

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

最佳答案

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

Why is there a ?: operator in the C language and why is it better than if-else?

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

"The conditional expression often leads to succinct code."

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

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 也没有真正提到为什么需要 ?: 运算符。它主要只是说明操作符的行为在新标准中已经改变:

The syntactic restrictions on the middle operand of the conditional operator have been relaxed to include more than just logical-OR-expression: several extant implementations have adopted this practice.

The type of a conditional operator expression can be void, a structure, or a union; most other operators do not deal with such types. The rules for balancing type between pointer and integer have, however, been tightened, since now only the constant 0 can portably be coerced to a pointer.

因此,如果有人有对结构或 union 类型执行算术的冲动,那么 ?: 据说比 if-else 更方便。我看不出这有什么明显的好处,但至少这是运营商存在的一些理由。

接下来的问题是:

Why is there a compiler extension to the ?: operand in the GCC compiler?

提到这个问题的答案here :

When it becomes useful is when the first operand does, or may (if it is a macro argument), contain a side effect. Then repeating the operand in the middle would perform the side effect twice. Omitting the middle operand uses the value already computed without the undesirable effects of recomputing it.

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

然后尝试回答原始问题:

Why doesn't GCC's ternary extension support assignment?

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

这是一个非常狭窄且值(value)有限的功能。它可能在某些特殊的嵌入式系统情况下有用,在这种情况下,您可以在要求苛刻的实时系统中读取硬件寄存器……除此之外,我认为它没有用处。

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

关于c - 为什么 GCC 的三元扩展不支持赋值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16925429/

相关文章:

c++ - 除了LAME MP3之外,还有哪些开源的C/C++音频压缩选项?

c++ - C++ 中的纯/常量函数

c++ - 编译器可以忽略 constexpr 函数中 "not-taken"分支的评估吗?

javascript - 这两者是否相同,或者其中一个比另一个更好/更安全?

c - 将 WIN32 应用程序移植到 Linux - 事件在 Linux 中如何工作?

c - 为什么不能使用 $ 识别 Makefile 中规则的右侧?

c++ - 如何在 C++ 中打印编译时计算的结果?

linux - 交叉编译 node.js 到 MIPS 24Kc V5.0

swift - 尝试分配给可选属性时类型不匹配

C——换档动力操作