c-如果前面有静态声明,为什么隐式外部声明无效



考虑以下示例程序:

#include <stdio.h>
static int n = 123;
extern int n;
int main(void) { printf("n is %dn", n); return 0; }

gcc -std=c99 -pedantic myprog.c编译成功。根据C99§6.2.2标识符的链接,第4部分:,n具有静态链接

对于在该标识符的先前声明可见的范围中使用存储类说明符extern声明的标识符,如果先前声明指定内部或外部链接,则该标识符在随后声明中的链接与在先前声明中指定的链接相同。如果没有可见的先前声明,或者先前声明未指定链接,则标识符具有外部链接。

现在删除extern:

#include <stdio.h>
static int n = 123;
int n;
int main(void) { printf("n is %dn", n); return 0; }

此程序不可编译。GCC给出以下错误:

myprog.c:4:5: error: non-static declaration of ‘n’ follows static declaration
4 | int n;
|     ^
myprog.c:3:12: note: previous definition of ‘n’ was here
3 | static int n = 123;
|   

为什么会出现此错误?我认为第二个程序中的int n;应该等同于extern int n;。根据C99标准,§6.2.2标识符的链接,第5部分:

如果对象的标识符声明具有文件作用域且没有存储类说明符,则其链接是外部的。

您已经在标准中找到了相关的部分。§4说,如果你声明它为extern,并且已经声明了一个内部链接变量,那么你的extern的链接也变成了内部链接——所以它会引用同一个变量,就像你写了两次static int n;一样。

这些规则有点混乱,像这样的古怪功能已经过时了。我不知道它为什么会出现在那里的历史原因。

6.11.2标识符的链接
在没有static存储类说明符的情况下,在文件作用域声明具有内部链接的标识符是一项过时的功能。

在后一种情况下,您没有指定链接,因此这是一个暂定定义。根据你在§5中引用的部分,它得到了外部链接,然后你得到了与同一翻译单元中的内部链接标识符的命名冲突,因此产生了编译器错误。

最新更新