关于c语言中extern 声明的问题。

张为 发布于 2013/12/11 18:48
阅读 2K+
收藏 2
c

c中两个.c文件声明相同名字的外部变量和函数不加static的限定是可以互相调用的。那extern声明的作用是什么。

以下是问题补充:

@张为:比如file1.c要调用file2.c中的某一个函数。只需在file1.c要使用的地方声明这个函数,相同的函数名就可以调用了,不需要extern限定。或者在file1.c中前置声明一个函数加了extern限定。同样可以在file1.c中实现这个函数。那extern限定的具体作用是什么。 (2013/12/11 19:10)
加载中
1
JerryLin
JerryLin

int a; 这是declaration

int a = 1; 这是definition

a = 1; 这是assignment

extern int a; 这是global scope,对应file scope/ function scope/statement scope等等

compile 和  link 是两个阶段,external scope处理是在link阶段

static本质也是scope


张为
张为
回复 @JerryLin : 只能初始化一次 和默认为0我测试过 确实如此。Ritchie Kernighan的The C Programming Language 2ed也给出了说明。“在没有显式初始化的情况下,外部变量与静态变量都被初始化为0, 而自动变量与寄存器变量的初值则没有定义。“在一个源程序的所有源文件中对一个外部变量只能在某个文件中定义一次。”
JerryLin
JerryLin
回复 @张为 : 我不清楚你的结论是从哪里来的,c language spec 还是某个 implementation defined。我不记得标准里有外部变量只能初始化一次的限制,也没有外部变量默认值为0的要求。我认为这是个变量scope的问题,建议你找C语言最新标准来看看。
张为
张为
可是外部变量只能被初始化一次。那对于外部变量。int a;是declaration 还是definition呢。
张为
张为
可是对应的外部变量 如果没有显式的初始化 默认初始化为0。我试了在两个文件中 都不加extern的定义int a;外部变量是不会出错的。为什么?
0
张为
张为
@中山野鬼 请教个问题。多谢了。
0
中山野鬼
中山野鬼
c文件里面默认的非函数内的变量以及函数本身都是extern的。哈。对编译没有作用。另外如果是两个文件都有相同名称,记得是有调用优先级的。你查一下标准。
中山野鬼
中山野鬼
@eel 这个是的,会给 warning的。。哈
修改登录密码
修改登录密码
回复 @中山野鬼 : 像这个代码: extern int *p; p++; 如果没有extern int p声明, 你怎么知道p到底是+1 还是+4呢?
中山野鬼
中山野鬼
回复 @eel : 你这个解释我没具体看过。一般不属于本次编译文件的,我看的反汇编,是通过二次读取的。留的都是地址指针,在链接时,再确定具体地址。哈。
修改登录密码
修改登录密码
extern对编译有作用。 因为编译器第一次扫描到这个符号的时候,可能不知道这个外部符号占用多大存储空间。extern可以告诉编译器为这个符号预留正确的内存空间
中山野鬼
中山野鬼
回复 @张为 : 可以这么说。哈。
下一页
0
後方之水
後方之水
extern对函数来说是可有可无。但extern int a;是声明,int a;是定义
後方之水
後方之水
回复 @eel : http://stackoverflow.com/a/3367584
修改登录密码
修改登录密码
绝非可有可无的。 比如对一个函数f(double a, double b) 如果在其他文件里没有extern声明, 编译会通过,但很可能会导致运行错误。 只不过大多数情况下,函数参数的宽度都不超过32位,也不会有问题。
0
泡不烂的凉粉
泡不烂的凉粉
extern 对函数也有用. 可以用来声明外部函数. 否则编译的时候要碰见提示. 
0
c
chenruibuaa

1. 变量必须先声明再使用,大多数编译器中,不加extern的声明都是定义,是占用数据空间的。如果你在a.c里定义了int a,在b.c中要使用就必须先声明extern int a;

2. 函数默认的存储修饰符就是extern,可以不声明函数就使用,但是编译器会插入一个隐式声明,形如int func(void),这样就无法进行正确的类型检查,容易在运行时出错。

张为
张为
回复 @eel : cc -c a.c , cc -c b.c , cc a.o b.o -o b_exe. 这个最后一步不算链接么?
修改登录密码
修改登录密码
回复 @张为 : cc只是编译 没有连接
张为
张为
回复 @eel : 文件a.c 中 “int g_i = 1;” 文件b.c中 “#include <stdio.h> int g_i; int main(){printf("%d", g_i);}” 编译 cc a.c b.c
修改登录密码
修改登录密码
回复 @张为 : 你最好贴出你的编译步骤和选项 不然都不知道你错在哪了
张为
张为
回复 @chenruibuaa : gcc也没有出错啊
下一页
0
jingshishengxu
jingshishengxu
不用extern的话,是两个不同的变量了吧
0
宏哥
宏哥

搞清了extern, static, 和指针

就明白了C语言

0
b
baibai2
明白啦,顶!
0
JerryLin
JerryLin

int a; 这是declaration <= 这个地方可能我有错,看spec时有这个印象,没考证
我和你方向上有偏差,我是想解释:某个全局变量,其定义只能在一个地方(C文件),其他地方如果想看到它,需要通过申明的方式告诉编译器这个全局变量的存在,extern关键字就是这个作用。在例子里,extern int a;可以让没有定义这个全局变量的C文件知道外部有这个变量,编译器编译时不会报错,连接器会在连接多个obj编译结果时处理变量访问地址的问题。
int a = 1; 这个表达式,定义/初始化都包含了;extern int a;只是个申明;extern int a = 1这个会报错。你是这个意思?

张为
张为
回复 @JerryLin : 嗯这样是会报错的。问题的关键是我上条回复中说的 c陷阱与缺陷一书的解释。 我已经明白怎么回事了。
JerryLin
JerryLin
回复 @张为 : 你试试在a.c中初始化int a = 1;在b.c中初始化int a = 2;然后先编译(我用gcc)gcc -c ,然后再连接 gcc -o
张为
张为
多谢你的耐心解答。我在c陷阱与缺陷 这书中找到了解释。这个是和系统有关系的。里面解释的 “如果一个外部变量在多个源文件中定义却没有指定初始值,那么某些系统会接受这个程序,而另外一些系统则不接受。” 所以让我困惑的问题是系统机制问题。 听你解释我已经大概明白extern用法了。再次感谢。
张为
张为
前面讨论的是在a.c b.c中都是定义的int a;外部变量。
张为
张为
如果我在a.c 中 显式的初始化 int a = 1; 在b.c中 int a; 不加extern 也是调用的a.c 中的a 也没有报错 警告也没有。 我用的clang编译器
下一页
返回顶部
顶部