问题
多文件编写时为什么 多个.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 链接时所需要的库

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐