Aar*_*ell 2 c parsing initialization assignment-operator language-lawyer
像这样组合声明和赋值是很常见的:
int beans = a * 2;
Run Code Online (Sandbox Code Playgroud)
或分开,像这样
int beans;
beans = a * 2;
Run Code Online (Sandbox Code Playgroud)
我目前的理解是bean可以被赋值,因为它是左值;它具有可写入的存储空间。右值a * 2
无法分配给它,因为它只是一个带有值的表达式,没有存储空间。因此,这是允许的:
int beans;
(beans) = a * 2;
Run Code Online (Sandbox Code Playgroud)
事实上,任何作为左值的左操作数都应该有效。现在,这似乎表明int beans;
是一个表达式,也是一个左值。但是,这是不允许的:
(int beans) = a * 2;
Run Code Online (Sandbox Code Playgroud)
就 C 解析器的设计方式而言,这表明声明不仅仅是带有左值的表达式。这里发生了什么?
该声明
beans = a * 2;
Run Code Online (Sandbox Code Playgroud)
包含很多表达方式。
主要表达式是赋值本身:beans = a * 2
。它又包含两个子表达式:beans
和a * 2
。乘法表达式本身有子表达式:a
和2
。
所有表达式都可以加括号,这意味着整个语句可能如下所示:
(beans) = ((a) * (2));
Run Code Online (Sandbox Code Playgroud)
这里所有的子表达式都被括号括起来。
现在我们来看看定义:
int beans;
Run Code Online (Sandbox Code Playgroud)
那不是一个表达。它不包含任何子表达式。它不能作为一个整体括起来。
另一方面,带有初始化的定义:
int beans = a * 2;
Run Code Online (Sandbox Code Playgroud)
确实包含一个表达式和子表达式。那是在右侧=
。所以我们可以将其写为:
int beans = ((a) * (2));
Run Code Online (Sandbox Code Playgroud)
但同样,变量声明部分不是表达式,并且不能用括号括起来。
另请注意,=
定义中不是赋值。这是初始化。这两个不同的术语表明存在语义差异。
正如乔纳森·莱夫勒 (Jonathan Leffler) 在评论中提到的。声明的声明符部分可以用括号括起来。
对于像这样的简单声明
int beans;
Run Code Online (Sandbox Code Playgroud)
使用它确实没有任何意义。但对于诸如函数指针或数组指针之类的东西,它会产生很大的差异。
例子:
int *foo(int x);
Run Code Online (Sandbox Code Playgroud)
它声明了一个函数,该函数接受一个int
参数并返回一个指向 的指针int
。与以下内容进行比较:
int (*foo)(int x);
Run Code Online (Sandbox Code Playgroud)
它声明了一个变量,它是一个指向函数的指针。该函数接受一个int
参数,并返回一个int
值。