4952|18

6366

帖子

4912

TA的资源

版主

楼主
 

正确理解.c文件和.h文件 [复制链接]

 
正确理解.c文件和.h文件


C编译器角度看,.h.c皆是浮云,就是改名为.txt.doc也没有大的分别。换句话说,就是.h.c没啥必然联系。.h中一般放的是同名.c文件中定义的变量、数组、函数的声明,需要让.c外部使用的声明。这个声明只是让需要用这些声明的地方方便引用。因为 #include "xx.h" 这个宏其实际意思就是把当前这一行删掉,把 xx.h 中的内容原封不动的插入在当前行的位置。由于想写这些函数声明的地方非常多(每一个调用 xx.c 中函数的地方,都要在使用前声明一下子),所以用 #include "xx.h" 这个宏就简化了许多行代码——让预处理器自己替换好了。也就是说,xx.h 其实只是让需要写 xx.c 中函数声明的地方调用(可以少写几行字),至于 include 这个 .h 文件是谁,是 .h 还是 .c,还是与这个 .h 同名的 .c,都没有任何必然关系。
  这样你可能会说:啊?那我平时只想调用 xx.c 中的某个函数,却 includexx.h 文件,岂不是宏替换后出现了很多无用的声明?没错,确实引入了很多垃圾 ,但是它却省了你不少笔墨,并且整个版面也看起来清爽的多。鱼与熊掌不可得兼,就是这个道理。反正多些声明(.h一般只用来放声明,而放不定义)也无害处,又不会影响编译,何乐而不为呢?
举例:
//a.h
void foo();

//a.c
#include "a.h" //我的问题出来了:这句话是要,还是不要?
void foo()
{
return;
}

//main.c
#include "a.h"
int main(int argc, char *argv[])
{
foo();
 return 0;
}
针对上面的代码,请回答三个问题:
a.c 中的 #include "a.h" 这句话是不是多余的?
为什么经常见 xx.c 里面 include 对应的 xx.h
如果 a.c 中不写,那么编译器是不是会自动把 .h 文件里面的东西跟同名的 .c 文件绑定在一起?
解答:
答:不一定。这个例子中显然是多余的。但是如果.c中的函数也需要调用同个.c中的其它函数,那么这个.c往往会include同名的.h,这样就不需要为声明和调用顺序而发愁了(C语言要求使用之前必须声明,而include同名.h一般会放在.c的开头)。有很多工程甚至把这种写法约定为代码规范,以规范出清晰的代码来。
答:1中已经回答过了。
答:不会。




最新回复

HENHAO   详情 回复 发表于 2014-10-17 23:48
点赞 关注
 
 

回复
举报

674

帖子

5

TA的资源

纯净的硅(初级)

沙发
 
精辟啊精辟!真得赞一个,很显而易懂!
 
 
 

回复

1297

帖子

2

TA的资源

纯净的硅(中级)

板凳
 
头文件的函数申明中啥时候要家extern啊?
 
 
 

回复

8

帖子

0

TA的资源

一粒金砂(初级)

4
 
好东西啊,这是
 
 
 

回复

6366

帖子

4912

TA的资源

版主

5
 
johnrey 发表于 2014-9-21 13:05
头文件的函数申明中啥时候要家extern啊?

全局变量,在别的文件中要用到这个变量时,要加EXTERN,表示这个变量是在别的文件中定义过的。
 
 
 

回复

1297

帖子

2

TA的资源

纯净的硅(中级)

6
 
tiankai001 发表于 2014-9-21 22:30
全局变量,在别的文件中要用到这个变量时,要加EXTERN,表示这个变量是在别的文件中定义过的。

我的主要疑问是,比如变量int a 在xx.c中定义,xx.h里面写了extern int a,包含在xx.c和main.c中,对main.c来说看到extern int a是外部变量,这是对的,
可是xx.h同时包含在xx.c中,xx.c怎么处理这个extern int a呢?会有问题吗?
 
 
 

回复

6366

帖子

4912

TA的资源

版主

7
 
johnrey 发表于 2014-9-21 23:06
我的主要疑问是,比如变量int a 在xx.c中定义,xx.h里面写了extern int a,包含在xx.c和main.c中,对main ...

变量的声明和定义一般在,c文件中,h文件一般不要声明变量。
一般在main.c中声明全局变量,在其他.c文件中定义这个全局变量时用extern说明。
在.h文件中,一般是定义常量和函数,最好不要定义变量
 
 
 

回复

6366

帖子

4912

TA的资源

版主

8
 
johnrey 发表于 2014-9-21 23:06
我的主要疑问是,比如变量int a 在xx.c中定义,xx.h里面写了extern int a,包含在xx.c和main.c中,对main ...

比如a.c中有int a =1;如果b.c中要用到a=1;那么就可以extern int a;这样b.c就引用声明了a.c中的a
 
 
 

回复

1297

帖子

2

TA的资源

纯净的硅(中级)

9
 
tiankai001 发表于 2014-9-22 08:22
变量的声明和定义一般在,c文件中,h文件一般不要声明变量。
一般在main.c中声明全局变量,在其他.c文件 ...

了解,谢谢
 
 
 

回复

6366

帖子

4912

TA的资源

版主

10
 
本帖最后由 tiankai001 于 2014-9-22 11:09 编辑

为了更好地说明.c和.h的联系和区别,我又搜集了几篇相关的文章。
希望能够帮助你彻底搞明白这个问题

如果觉得不错的话,别忘了给个“赞”哦!
 
 
 

回复

1100

帖子

3

TA的资源

五彩晶圆(初级)

11
 
牛叉,一语道破天机
 
 
 

回复

167

帖子

1

TA的资源

一粒金砂(中级)

12
 
赞一个,楼主总结的很好
 
 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

13
 
1.
一般来说
.c是模块的实现部分;
.h是模块的声明部分,即接口。

这作为一种公认的常用套路。

通常,发布一个库,如果只从使用者的角度来说,不管是开源还是闭源,调用者/使用者只关心 接口。
而只有 开源代码,并且有人关心实现部分,不论是验证还是学习实现方法,才会有人去看.c的代码部分。

当然也有的时候,.h里的一些带参宏本身构成了模块的主体功能。这个时候,.h也算得上一种实现。这是一个特别的例外,虽说特别,但却不少见。
比如 pthread 和 unity(不是3D引擎那个unity,是一个简单的c自动测试框架)

2.
另外,看到主题帖里,楼主提到一个,对于一个名叫的a的模块,其.c/.h
对于main模块来说(主调方),它include a.h是必要的,而a.c本身包含a.h则是多余的(在这个例子中)

如楼主所说,这的确是一个非常常见的惯常做法。
而且绝大多数时候这也不是多余的。
这主要是因为有很多时候,它的实现部分a.c同样要使用很多a.h自己为自己定义的 抽象或者 重定义数据类型,又或者是调用自己的部分子函数,诸如此类。
个人签名

强者为尊,弱者,死无葬身之地

 
 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

14
 
johnrey 发表于 2014-9-21 23:06
我的主要疑问是,比如变量int a 在xx.c中定义,xx.h里面写了extern int a,包含在xx.c和main.c中,对main ...

extern一个变量或者函数
其实是引用一个外部声明  extern就是 外部 的意思

要区分的是

变量(或函数) 的 定义 和 声明 是两回事

对于变量而言,定义 意味着 会伴随内存分配过程,对于同一个名字而言,这种行为在整个程序中只能发生一次(严格来说,是同一个作用域,比如说同一个函数内部的变量,或者是同一个源文件的 静态全局变量,或者是 整个项目的 全局变量(就是那些不加 static修饰 的 全局变量)

而声明,只是对一个名字的引用。
与内存分配无关,允许多次发生。

你提到的 xx.c中已经定义了,然后xx.h中extern,这个语法上没什么问题
自己定义,然后自己extern不会有太大问题。
只不过要注意先后顺序,因为xx.h的include一般会放在 xx.c的最开始的地方

假如出现这种情况就会报错。
因为你还没定义就先声明了。报错信息应该是 声明了未定义的标识。

其实只要理解 定义 和 声明 的 特点 和 关系,万变不离其宗,很好理解。



个人签名

强者为尊,弱者,死无葬身之地

 
 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

15
 
johnrey 发表于 2014-9-21 23:06
我的主要疑问是,比如变量int a 在xx.c中定义,xx.h里面写了extern int a,包含在xx.c和main.c中,对main ...

至于楼主说的 一般不要在.h中 定义变量
这是因为 .h一般会被各处引用,如果在这里定义变量很容易发生 重定义。

当然你也许会采取某些手段避免重定义,在那种情况下,我估计你是把 定义 变成了 声明。
或者是头文件的包含做了一些处理,使其在实际上并没有被多次单独包含。


个人签名

强者为尊,弱者,死无葬身之地

 
 
 

回复

6366

帖子

4912

TA的资源

版主

16
 
辛昕 发表于 2014-9-22 15:56
1.
一般来说
.c是模块的实现部分;

看来关于变量的声明和定义也要详细说一下,
变量到底是先声明还是先定义,声明和定义的异同点,什么情况下声明和定义是同时定义的,什么时候是只声明,什么时候是只定义?
这个也得好好说明,然后再来说这个问题就会比较明了
 
 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

17
 
tiankai001 发表于 2014-9-22 21:32
看来关于变量的声明和定义也要详细说一下,
变量到底是先声明还是先定义,声明和定义的异同点,什么情况 ...

请多多指教
个人签名

强者为尊,弱者,死无葬身之地

 
 
 

回复

6366

帖子

4912

TA的资源

版主

18
 

你说的非常好。
我的意思是,我应当再搜集一些这方面相关的资料,让大家更全面的了解这些
 
 
 

回复

2

帖子

0

TA的资源

一粒金砂(初级)

19
 
HENHAO
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表