我试图理解C语言中一元运算符背后的语法.根据此版本的标准link,在第6.5.3节中,一元运算符具有以下语法:

unary-expression:
  ...
  ++ unary-expression
  ...

这意味着从语法的Angular 来看,这样的事情是合法的: a = ++++b.然而,GCC编译器提供了这个错误:lvalue required as increment operand.

我真的不明白为什么?

根据标准,++b相当于(b += 1).这意味着a=++++b人应该扩大到a=((b+=1)+=1)人.为什么编译器会给出上述错误?

推荐答案

为了全面解释这一点,它把我们带到了相当深的语言律师领域.我会试着一步一步地解释.

当预处理器解析表达式++++b时,它寻找将形成有效运算符的最长字符序列,即所谓的"最大咀嚼规则".在本例中,这意味着代码将被视为我们已经编写了++ ++b(而不是++ + +b或更多).

正如您从形式语法中注意到的,前缀++和--可以与其他一元表达式组合,因此我们得到了"从右到左的结合性",意思是(++(++b).然而,C语法只规定syntax-wise像这样组合多个一元操作符是可以的,但它是否是有效代码取决于单个操作符.

从那时起,我们将思考一些正式的C称为"左值"的东西,本质上是一个可修改的内存位置,而不是表达式的临时结果.例如,在有两个变量的情况下,ab分别是对象和左值,但加法表达式的结果不是.

让我们首先来看一个有效的表达式.如果您编写了++*ptr,那么这将是有效的C,因为本例中的两个一元运算符指定了以下内容:

C17 6.5.3.1,重点是地雷

Constraints
The operand of the prefix increment or decrement operator shall have atomic, qualified, or unqualified real or pointer type, and shall be a modifiable lvalue.

C17 6.5.3.2,重点是地雷

The unary 100 operator denotes indirection.如果操作数指向一个函数,则结果是一个函数指示符;if it points to an object, the result is an lvalue指定该对象.

所以前缀++期望一个可修改的左值,而前缀*提供了这个,所以++*ptr是好的.

然而,在++++b的情况下,第一个++b的结果是一个左值not.因此,通过在第一个上添加另一个++,我们违反了上面引用的约束,这意味着代码是无效的C.

那么,为什么++b的结果不是最重要的呢?6.5.3.1说的是:

前缀++运算符的操作数的值递增.结果是递增后的操作数的新值.表达式++E相当于(E+=1).

Ok so we have to go dig up the rules of += (compound) assignment operators...
We find the relevant explanation in C 17 6.5.16, emphasis mine:

赋值运算符将值存储在由左操作数指定的对象中.赋值表达式的赋值后左操作数的值为but is not an lvalue.

因此,由于违反约束,编译器必须提供诊断消息.我们没有违反语法规则,但我们违反了约束.如果您希望将代码称为严格符合的C程序,则语法和约束都是一种"不允许异常".

C++相关问答推荐

为什么海湾合作委员会在共享对象中的. init_data的虚拟内存地址之前留出一个空白

当打印字符串时,为什么在c中没有使用常量限定符时我会收到警告?

为什么在Linux(特别是Ubuntu 20.04LTS)上,POSIX共享内存对象在重启后仍然存在,然后突然变成了根用户?

C:fopen是如何实现二进制模式和文本模式的?

识别和处理c中整数溢出的最佳方法?

在C语言中,在数学运算过程中,为什么浮点数在变量中的行为不同

Rust FFI--如何用给出返回引用的迭代器包装C风格的迭代器?

如何在不使用其他数组或字符串的情况下交换字符串中的两个单词?

如何捕捉只有换行符或空格字符缓冲区的边缘大小写

在WSL关闭/重新启动后,是什么原因导致共享对象依赖关系发生更改?

当我用scanf(&Q;%S%S%S&Q;,单词0,单词1,单词2)输入多个单词时,除了最后一个单词外,每个单词的第一个字符都丢失了

错误:字符串在C中获得意外输出

如何修复我的qsort()算法?它每次都给出不同的结果

有没有办法减少C语言中线程的堆大小?

&stdbool.h&q;在嵌入式系统中的使用

try 判断长整数是否为素数

这些表达式是否涉及 C 中定义的复合文字?

为什么 int32_t 和 int16_t 在 printf 输出中具有相同的位数?

运行以下 C 程序时出现分段错误

如何在Linux上从控制台左上角开始打印文本?