编译过程 多个.c文件 . h文件 和main文件的 联系
问题多文件编写时为什么 多个.c 文件可以组合成为一个main.c 文件换句话说 主文件 main.c 怎么实现 将 多个 .c文件整合,而且是以包含这些 .c 文件的头文件 的方式, 而不是包含 其他.c文件的方式下面我以 add.cadd.hmain.c 文件为例add.h#ifndef __ADD__#define __ADD__intadd(int,int);#endif /*__ADD_
问题
多文件编写时为什么 多个.c 文件可以组合成为一个main.c 文件
换句话说 主文件 main.c 怎么实现 将 多个 .c文件 整合,而且是以包含这些 .c 文件的头文件 的方式, 而不是包含 其他 .c文件的方式
下面我以 add.c add.h main.c 文件为例
add.h
#ifndef __ADD__
#define __ADD__
int add(int,int);
#endif /*__ADD__*/
其中add.c
#include"add.h"
int add(int a,int b)
{
return a+b;
}
main .c
#include<stdio.h>
#include"add.h"
int main()
{
int a=6;
int b=7;
int sum=add(a,b);
printf("sum=%d",sum);
}
我们将 实现两数相加的add 函数 ,实现放在.c 文件中 函数声明放在 .h文件中
我们需要借助 gcc 来窥探 当一个 .c文件包含头文件,且在预处理的过程中会发生什么。
当我们执行如下语句
gcc -E main.c -o main1.i
我们会得到 一个 main1.i 的 c文件
使用
cat main1.i
查看文件包含内容
# 4 "add.h"
int add(int,int);
# 4 "main.c" 2
int main()
{
int a=6;
int b=7;
int sum=add(a,b);
printf("sum=%d",sum);
}
我们发现 main1.i 将 add头文件的内容 展开了。 (实际上,为了展示的需要我们省略了 stdio.h
头文件所展开的代码)
我们再对 add.c 进行预处理
gcc -E add.c -o add1.i
查看add .i 文件代码
cat add1.i
1 "add.h" 1
int add(int,int);
# 2 "add.c" 2
int add(int a,int b)
{
return a+b;
}
可见 add.c 在预处理之后也会将 头文件展开
当我们把main.c 和add.c 都进行 预处理的时候 ,他们都将会拥有 add 的头文件所包含的那部分代码
这样main .c 就和 add.c 建立起了联系。
当 存在多个像add .c 这样的 .c文件 多个像 add.h这样的 .h 文件时, 且main.c 同样包含了所有的.h ,每个.c 文件同样包含了与其对应的头文件 时。 我们就能发现 main .c 通过 .h 文件 引用到了 其他.c 文件中的 代码(实现代码)
简言之
.h文件中的所有内容会被写到包含它的.c文件中,而所有的.c文件以一个共同的main函数作为可执行程序的入口。
具体的解释
比方说 我在add.h里定义了一个函数的声明,然后我在aaa.h的同一个目录下建立add.c , add.c里定义了这个函数的实现,然后是在main函数所在.c文件里#include这个add.h 然后我就可以使用这个函数(add.c))了。
main在运行时就会找到这个定义了这个函数的add.c文件。这是因为:main函数为标准C/C++的程序入口,编译器会先找到该函数所在的文 件。
假定编译程序编译myproj.c(其中含main())时,发现它include了mylib.h(其中声明了函数void test()),那么此时编译器将按照事先设定的路径(Include路径列表及代码文件所在的路径)查找与之同名的实现文件(扩展名为.cpp或.c,此
例中为mylib.c),如果找到该文件,并在其中找到该函数(此例中为void test())的实现代码,则继续编译;
如果在指定目录找不到实现文件,或者在该文件及后续的各include文件中未找到实现代码,则返回一个编译错误.其实include的过程完全可以“看成”是一个文件拼接的过程,将声明和实现分别写在头文件及C文件中,或者将二者同时写在头文件中,理论上没有本质的区别。
需要明白的是 每一个 .c文件都是一个 编译单元
当多个.c 文件经历 预处理、编译、汇编 (test.c test.h => test.i => test.s => test.o
最终转变为多个 .o 文件时 。就要经历 链接这一步了
连接阶段,将各个目标文件中的各段代码进行绝对地址定位,生成跟特定平台相关的可执行文件,编译器在编译时是以C文件为单位进行的.,也就是说如果你的项目中一个C文件都没有,那么你的项目将无法编译,连接器是以目标文件为单位,它将一个或多个目标文件进行函数与变量的重定位,生成最终的可执行文件,在PC上的程序开发,一般都有一个main函数,这是各个编译器的约定。为了生成一个最终的可执行文件,就需要一些目标文件,也就是需要C文件,而这些C文件中又需要一个main函数作为可执行程序的入口。
最终的最终,我们将多个 .o 文件进行链接 ,变为可执行文件。
最后 以创建静态库 为例
我们创建静态库 首先 : 将多个 .c 文件变成 .o文件
然后利用 ar -rcs 指令 生成指定的 静态库
最后利用静态库 只需要 静态库,静态库包含的头文件 ,还有你准备用来测试 静态库的 .c
文件,当然 你的.c 测试文件 需要包含上述的头文件 才能达到测试静态库的目的
gcc test.c -I所需要使用的头文件 -L链接库所在目录 -l 链接时所需要的库
更多推荐
所有评论(0)