例如我们有这样的代码:
#include <stdio.h>
int main(void)
{
int n = 4;
{
n++;
}
printf("%d\n",n);
return 0;
}
内部代码块如何看待变量 n?C 语言标准对此是如何解释的?我一直在寻找这个问题的答案。在我看来,答案如下:在 C17 中,我们有(6.8 #3):
块允许将一组声明和语句组合成一个语法单元。具有自动存储期的对象的初始化器,以及具有块作用域的普通标识符的变长数组声明器,在每次按声明顺序到达时都会被求值,并将值存储在对象中(包括在没有初始化器的对象中存储不确定的值),就像它是一个语句一样,并且在每个声明中,都按照声明器出现的顺序进行。
如果不考虑初始化器,那么块实际上只是几个语句。我们只是使用一个块将所有这些运算符作为一个语法单元进行评估。换句话说,如果删除块中的 {} 字符,这些将是相同的运算符,结果将完全相同,但这些运算符不会在一个语法单元中进行评估:
#include <stdio.h>
int main(void)
{
int n = 4;
n++; // same effect but without {}
printf("%d\n",n);
return 0;
}
我们还有(6.2.1#4):
如果声明标识符的声明符或类型说明符出现在块内或函数定义中的参数声明列表中,则该标识符具有块作用域,该作用域在关联块的末尾终止。
由此我们了解到 n 具有块作用域。
如果我们将以上所有内容结合起来,就会发现 n 会增加,就好像增量运算符从未出现在内部块中一样。
这个答案正确吗?如果不正确,请解释原因。并请引用一段 C 语言标准中的文字。
因为内部块是外部块(即本例中的函数体)的一部分。
C 标准的第 6.2.1p4 节描述了块范围:
所以 的作用域
n
是函数体所在的块main
,包括包含该语句的块n++
。请注意,以下内容可能看起来更熟悉,但在范围方面是相同的:
在这种情况下,块是
if
语句的“语句”部分,并且如上所述,该块是函数体的“内部”范围。这是一个范围问题:
(C23 6.2.1/2)
您已经引用了(来自 6.2.1/4) 的部分,该部分(主要)定义了块级作用域变量(例如 )的作用域
n
。它结束于最内层封闭块的末尾。整个嵌套块都位于该作用域内,因此n
在那里可见。是的,在你的例子中。像你这样的裸块作用不大,但它可以有效地限制其中声明的变量的范围。
但在更常见的块用法中,你不能随意删除括号。块是函数体必须使用的代码块。如果删除块中的括号
if
,多语句else
块和循环体的含义将有所不同。例如,这个……... 产生的输出与此不同:
事实上,降低引入此类错误的风险是常见样式规则的原因之一,即
if
,、else
和循环体应始终是块,即使块仅包含单个语句。有点儿像。不清楚你认为替代方案是什么。不过,在
n++
块内部执行的效果和没有直接包含它的块时是一样的。如果你想要不同的效果,那么你可以n
在块内部声明一个不同的值。来自 C23 标准(6.2.1 标识符、类型名称和复合文字的范围)
和
在你的例子中,变量
n
并没有隐藏在内部块作用域中。如果你改写成那么在内部块作用域中声明的变量
n
将隐藏在外部作用域中声明的同名变量。或者更有趣的例子
在这种情况下,您将获得与原始程序相同的结果
顺便说一句,您可以在内部作用域中重新引入一个具有文件作用域并且隐藏在内部块作用域的某些封闭块中的变量。
给你。