讨论——extern与头文件(×.h)区别与联系

[复制链接]
974|19
手机看帖
扫描二维码
随时随地手机跟帖
chuntian2016|  楼主 | 2016-9-23 20:29 | 显示全部楼层 |阅读模式
如题, 这个关于头文件的我相信搞开发的都不陌生的,这个extern关键字的也不陌生的,,不过这两者有啥联系的,又有啥区别的呢?
在这里跟大家一块的探讨下的了。。。
chuntian2016|  楼主 | 2016-9-23 20:31 | 显示全部楼层
我们在程序设计中常常会有这两个疑问的:
用#include可以包含其他头文件中变量、函数的声明,为什么还要extern关键字?
如果我想引用一个全局变量或函数a,我只要直接在源文件中包含#include<xxx.h> (xxx.h包含了a的声明)不就可以了么,为什么还要用extern呢??

使用特权

评论回复
chuntian2016|  楼主 | 2016-9-23 20:32 | 显示全部楼层
是啊,有了头文件的,又去用extern关键字的,是不是重复申明了呢?其实不然的。。。。

使用特权

评论回复
chuntian2016|  楼主 | 2016-9-23 20:33 | 显示全部楼层
先说下头文件,其实头文件对计算机而言没什么作用,她只是在预编译时在#include的地方展开一下,没别的意义了,其实头文件主要是给别人看的。
我做过一个实验,将头文件的后缀改成xxx.txt,然后在引用该头文件的地方用#include"xxx.txt"    编译,链接都很顺利的过去了,由此可知,头文件仅仅为阅读代码作用,没其他的作用了!
很神奇吧。。

使用特权

评论回复
chuntian2016|  楼主 | 2016-9-23 20:34 | 显示全部楼层
不管是C还是C++,你把你的函数,变量或者结构体,类啥的放在你的.c或者.cpp文件里。然后编译成lib,dll,obj,.o等等,然后别人用的时候,最基本的gcc hisfile.cpp yourfile.o|obj|dll|lib 等等。
       但对于我们程序员而言,他们怎么知道你的lib,dll...里面到底有什么东西?要看你的头文件。你的头文件就是对用户的说明。函数,参数,各种各样的接口的说明。

使用特权

评论回复
chuntian2016|  楼主 | 2016-9-23 20:35 | 显示全部楼层
那既然是说明,那么头文件里面放的自然就是关于函数,变量,类的“声明”(对函数来说,也叫函数原型)了。记着,是“声明”,不是“定义”。

       那么,我假设大家知道声明和定义的区别。所以,最好不要傻嘻嘻的在头文件里定义什么东西。比如全局变量:
/*xx头文件*/
#ifndef _XX_头文件.H
#define _XX_头文件.H
int A;
#endif
很糟糕的是,这里的int A是个全局变量的定义,所以如果这个头文件被多次引用的话,你的A会被重复定义,显然语法上错了。只不过有了这个#ifndef的条件编译,所以能保证你的头文件只被引用一次,不过也许还是不会出岔子,但若多个c文件包含这个头文件时还是会出错的,因为宏名有效范围仅限于本c源文件,所以在这多个c文件编译时是不会出错的,但在链接时就会报错,说你多处定义了同一个变量。。。。

使用特权

评论回复
chuntian2016|  楼主 | 2016-9-23 20:36 | 显示全部楼层
下边再说下extern关键字的

在定义变量的时候,这个extern居然可以被省略(定义时,默认均省略);在声明变量的时候,这个extern必须添加在变量前,所以有时会让你搞不清楚到底是声明还是定义。或者说,变量前有extern不一定就是声明,而变量前无extern就只能是定义。注:定义要为变量分配内存空间;而声明不需要为变量分配内存空间。
这里面的说明很重要的,用心体会的。。

使用特权

评论回复
chuntian2016|  楼主 | 2016-9-23 20:38 | 显示全部楼层
下面分变量和函数两类来说:

(1)变量

尤其是对于变量来说。
extern int a;//声明一个全局变量a
int a; //定义一个全局变量a

extern int a =0 ;//定义一个全局变量a 并给初值。
int a =0;//定义一个全局变量a,并给初值,

        第四个 等于 第 三个,都是定义一个可以被外部使用的全局变量,并给初值。
不论怎样,,,不管是int a;还是extern int a=0;还是int a=0;都只能出现一次,而那个extern int a可以出现很多次。

使用特权

评论回复
chuntian2016|  楼主 | 2016-9-23 20:38 | 显示全部楼层
总结下这个的——当你要引用一个全局变量的时候,你就必须要声明,extern int a; 这时候extern不能省略,因为省略了,就变成int a;这是一个定义,不是声明。注:extern int a; 中类型int可省略,即extern a; 但其他类型则不能省略。

使用特权

评论回复
chuntian2016|  楼主 | 2016-9-23 20:39 | 显示全部楼层
(2)函数
       函数,对于函数也一样,也是定义和声明,定义的时候用extern,说明这个函数是可以被外部引用的,声明的时候用extern说明这是一个声明。 但由于函数的定义和声明是有区别的,定义函数要有函数体,声明函数没有函数体(还有以分号结尾),所以函数定义和声明时都可以将extern省略掉,反正其他文件也是知道这个函数是在其他地方定义的,所以不加extern也行。

使用特权

评论回复
chuntian2016|  楼主 | 2016-9-23 20:40 | 显示全部楼层
说了这么多的,还是归纳一下的比较好理解的:

对变量而言,如果你想在本源文件(例如文件名A)中使用另一个源文件(例如文件名B)的变量,方法有2种:(1)在A文件中必须用extern声明在B文件中定义的变量(当然是全局变量);(2)在A文件中添加B文件对应的头文件,当然这个头文件包含B文件中的变量声明,也即在这个头文件中必须用extern声明该变量,否则,该变量又被定义一次。

使用特权

评论回复
chuntian2016|  楼主 | 2016-9-23 20:41 | 显示全部楼层
对函数而言,如果你想在本源文件(例如文件名A)中使用另一个源文件(例如文件名B)的函数,方法有2种:(1)在A文件中用extern声明在B文件中定义的函数(其实,也可省略extern,只需在A文件中出现B文件定义函数原型即可);(2)在A文件中添加B文件对应的头文件,当然这个头文件包含B文件中的函数原型,在头文件中函数可以不用加extern。

用extern 关键字定义变量跟函数的时候一定要注意的啊

使用特权

评论回复
chuntian2016|  楼主 | 2016-9-23 20:43 | 显示全部楼层
说了,这么多的,还是回到我们前边提的问题本身的两个疑问的,我给个比较通俗易懂的解释总结下的

如果一个文件(假设文件名A)要大量引用另一个文件(假设文件名B)中定义的变量或函数,则使用头文件效率更高,程序结构也更规范。其他文件(例如文件名C、D等)要引用文件名B中定义的变量或函数,则只需用#include包含文件B对应的头文件(当然,这个头文件只有对变量或函数的声明,绝不能有定义)即可。

使用特权

评论回复
cos12a| | 2016-9-24 13:27 | 显示全部楼层
个人感觉就是一种约定,防止出错和重复还有方便理解程序。

使用特权

评论回复
yu515301489| | 2016-9-24 15:12 | 显示全部楼层
发的东西不少啊~

使用特权

评论回复
yu515301489| | 2016-9-24 15:21 | 显示全部楼层
cos12a 发表于 2016-9-24 13:27
个人感觉就是一种约定,防止出错和重复还有方便理解程序。

正解,方便调用,方便理解函数内容功能。

使用特权

评论回复
reverse_L0111| | 2016-9-24 16:14 | 显示全部楼层

使用特权

评论回复
vivilzb1985| | 2016-9-25 12:43 | 显示全部楼层
chuntian2016 发表于 2016-9-23 20:31
我们在程序设计中常常会有这两个疑问的:
用#include可以包含其他头文件中变量、函数的声明,为什么还要ext ...

一般情况下,都是直接在头文件中的直接声明的。

使用特权

评论回复
firstblood| | 2016-9-25 17:59 | 显示全部楼层
extern关键字的就是一个外部引用声明的,在某种程度上说跟头文件是一致的。

使用特权

评论回复
comeon201208| | 2016-9-25 18:01 | 显示全部楼层
chuntian2016 发表于 2016-9-23 20:33
先说下头文件,其实头文件对计算机而言没什么作用,她只是在预编译时在#include的地方展开一下,没别的意义 ...

这种情况的我还没试验过的,下去验证下的在说,可以加深理解的。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

25

主题

1485

帖子

1

粉丝