xx.h和xx.c的奥妙
示例代码:
/********************* A.h*********************/ #define __A_H__
void fun(); #endif |
/********************* A.c*********************/ #include "a.h" //为什么要加? void fun() { return; } |
/******************** main.c********************/ #include "a.h" int main( ) { fun(); return 0; } |
为什么经常见xx.c里面include对应的xx.h?A.c中的#include "A.h"是否多余?
主要有两种原因:
①如果.c中的函数也需要调用同个.c中的其他函数,那么这个.c往往会include同名的.h,避免声明和调用顺序出现问题(C语言要求使用之前必须声明,而include同名.h一般会放在.c的开头)。
②.c中的函数中经常会使用了同名.h文件定义的宏,或者typedef定义的新类型。
有很多工程甚至把这种写法约定为代码规范,以规范出清晰的代码来。
由此,有很多工程甚至把这种写法约定为代码规范,以规范出清晰的代码来。以上示例中,显示是可有可无的。
从C编译器角度看,.h和.c只是后缀符号,毫无意义。换句话说,就是.h和.c没有必然联系。
1.预处理
预处理只是简单的替换,#include "xx.h"中所包含的完全展开到包含它的.c 文件中。.h只起到这个作用。
2.编译过程
以一个文件为基本的一个编译单元。一个.c文件生成一个.o文件,在编译阶段,只要.c或者包含的.h中已经声明的函数或变量,.c都会生成相应的.o文件。编译阶段对函数或变量的定义并无要求,所以在main.c中,即便void fun()是在A.c中定义的,但其包含的头文件中已经声明,即可顺利编译。
3.连接过程
将A.o和main.o结合起来,生成可执行文件。
若只是声明,没有在其他的.c中定义,连接时就会出错。也就是说若void fun()没有在A.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中的某个函数,就直接包含include了xx.h,宏替换后也可能会出现了很多无用的声明,不过这样整个版面很清晰。多些声明(.h一般只用来放声明,而放不定义)没有任何坏处,不会影响编译。