我有以下程序在两个文件中:
a.c
#include<stdio.h>
#include"b.c"
int main(void){
extern int a;
a+=2;
printf("%d\n",a);
return 0;
}
b.c
int a=1;
现在我使用 extern 关键字来声明变量 a,但不定义它。 因此,我可以更改其内容,并且打印它会打印 3.
我不明白的是,如果我从 a.c 中删除
extern int a;
行,程序也会运行,并且输出仍然是 3。
我认为要更改 b.c 中的变量,必须使用 extern 关键字。
这里发生了什么?
以这个程序为例:
#include<stdio.h>
void main()
{
extern int y;
printf("%d",y);
}
int y=10;
输出如下所示:
10
extern
是一个声明,而不是(必然)一个定义。
单独使用时,
extern
不会定义变量,这意味着它不会为其分配内存地址。它只是声明变量,以便您可以使用它。
在您的示例中,您不必声明
a
,原因很简单,它已经被定义了。
另一方面,如果
extern
变量立即分配给某个东西,它也会定义它。 (谢谢,@John Bollinger)
extern int b=20;
#include
指令未定义逻辑范围。
以一种简单(且正确)的理解,
#include
复制将代码从一个文件粘贴到您要运行的文件中。这意味着如果删除 extern
语句,就不会有问题,因为 a
已经由 int a=1;
定义了。将其视为通常使用全局变量。
另一方面,如果你移动
#include"b.c"
在程序的底部,您需要
extern
声明。如果没有它,编译器就不会知道 y
将在某个时刻被定义。该语句告诉编译器在发送错误告诉您变量不存在之前搜索声明。
事实上你正在编译:
#include<stdio.h>
int a = 1;
int main(void){
extern int a;
a+=2;
printf("%d\n",a);
return 0;
}
您只有一个编译单元,并且
a
未在另一编译单元中定义。
当您从声明中删除
extern
时,您定义了未初始化的局部自动变量 a
。然后你使用它,它就具有不可确定的价值。它可以是任何东西。
#include<stdio.h>
int a = 5;
int main(void){
int a;
a+=2;
printf("%d\n",a);
return 0;
}
这个程序不太可能输出
7
:https://godbolt.org/z/GeGvbd
当编译器编译
main
例程时,它已经在您包含的 int a=1;
中看到了 b.c
,因此 extern int a;
不会告诉它任何新内容。因此它不会做任何事情。
extern int a;
表示“a
是 int
的名称,而 int
是在其他地方定义的。”但是,通过包含 b.c
,您就包含了 int a=1;
,它定义了 a
。所以编译器已经知道 a
被定义为 int
。
我认为要更改 b.c 中的变量,必须使用 extern 关键字。
要按名称引用对象,您需要提供该名称的声明。您包含的
int a=1;
是一个声明(也是一个定义)。
您不需要
extern
来表示我将通过名称引用一个对象,但您确实需要它来表示“我不是在此处定义该对象,只是告诉您在某处定义的对象。”正确的使用方法不是将 b.c
包含在 a.c
中,而是:
b.c
中,用 a
定义 int a=1;
。b.h
中,用 a
声明 extern int a;
。a.c
中,使用 #include "b.h"
包含声明。a.c
中,您不需要自己编写 extern int a;
,因为当您包含 b.h
时您就会明白。b.c
中,使用#include "b.h"
检查声明。 (当您在 b.h
中包含 b.c
时,编译器将在同一编译过程中同时看到声明和定义,如果存在导致声明冲突的错误,它会发出警告。)