我在文件a.c中有以下程序:
#include<stdio.h>
#include"b.c"
int main(void){
extern int a;
a+=2;
printf("%dn",a);
return 0;
}
文件b.c如下:
int a=1;
现在我使用extern关键字来声明变量a,但没有定义它。因此,我可以更改它的内容,并且打印它将打印3。
我不明白的是,如果我从ac中删除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("%dn",a);
return 0;
}
您只有一个编译单元,并且a
没有在另一个编译单元中定义。
当您从声明中删除extern
时,您定义了未初始化的本地自动变量a
。然后你使用它,它的价值无法确定。它可以是任何东西
#include<stdio.h>
int a = 5;
int main(void){
int a;
a+=2;
printf("%dn",a);
return 0;
}
这个程序不太可能输出7
: https://godbolt.org/z/GeGvbd
当编译器正在编译main
例程时,它已经在您包含的b.c
中看到了int a=1;
,因此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
中,用int a=1;
定义a
。 - 在
b.h
中用extern int a;
声明a
。 - 在
a.c
中,使用#include "b.h"
包含声明。 - 在
a.c
中,你不需要自己编写extern int a;
,因为当你包含b.h
时,你会得到它。 - 在
b.c
中,使用#include "b.h"
检查声明。(当您在b.c
中包含b.h
时,编译器将在同一编译过程中同时看到声明和定义,如果存在导致声明冲突的错误,它将发出警告。)