我对extern的以下行为感到惊讶。
当我运行时
#include<stdio.h>
int main()
{
extern int a;
printf("%d\n", a);
return 0;
}
int a=20;
输出: 20(在gcc Linux 32位,看起来没问题)
但是当我在a
:
main()
时
#include<stdio.h>
int main()
{
extern int a;
int a=20;
printf("%d\n", a);
return 0;
}
输出:
extern.c: In function ‘main’:
extern.c:5:9: error: declaration of ‘a’ with no linkage follows extern declaration
extern.c:4:16: note: previous declaration of ‘a’ was here
为什么我在将a
的范围从全局更改为本地后立即收到错误?为什么它现在不允许重新声明a
,而在之前的情况下允许重新声明。
答案 0 :(得分:7)
extern
声明的要点是告诉编译器有关多个编译单元(.c
文件)使用的全局变量或函数,但是在单个编译单元中定义和分配。 extern
声明放在所有单元包含的头文件中,单个编译单元包含实际定义,因此同时看到两者。
您的第一个示例是合法C:您声明 a
将引用外部定义的变量,然后继续定义该变量当前的编译单位。通常情况下,extern
声明将包含在头文件中,因此在顶层显示给编译器,而不是在函数内部,但编译器无关紧要。换句话说,这里没有重新定义,只有声明后的定义。
您的第二个示例声明a
具有外部链接,然后继续将其定义为main
中的局部变量。声明和定义显然是不兼容的 - 如果a
是一个局部变量,它不能只在一个地方定义和分配 - 它会在每次调用函数时自动分配到堆栈上。这种不兼容性导致错误诊断。
答案 1 :(得分:4)
在第一个例子中,你告诉编译器:“嘿,我有一个名为a
的变量,它在其他地方定义。”然后你使用它。没关系。
#include<stdio.h>
int main()
{
extern int a;
printf("%d\n", a);
return 0;
}
int a=20;
在第二个示例中,您还告诉编译器程序中某处有一个名为a
的变量,然后在堆栈中声明一个具有相同名称的新变量。这没有多大意义,编译器说了两件事:在程序中找不到任何变量a
的声明,变量a
已经存在(如果你修复了第一个错误,它会)。
#include<stdio.h>
int main()
{
extern int a;
int a=20;
printf("%d\n", a);
return 0;
}
声明全局变量时,会在程序启动时分配其内存(它位于二进制文件中并映射到内存中)。声明局部变量时,在执行函数期间会在堆栈上分配内存。您不能将extern引用到尚不存在的变量。