概述
C语言程序从源文件经过编译、链接生成可执行文件。那么编译与链接分别做了什么? 开发中为什么使用.h编写函数的声明?接下来使用案例说清楚为什么这样编写代码。
C语言程序的编译和链接
C语言程序从源文件到生成可执行程序需要经过编译器的预处理,汇编、编译、链接。这里简化为编译、链接两个阶段
编译:对源文件语法做检查
链接:会查找函数的具体实现
并把项目中所有相关的.o目标文件、C语言函数库合并在一起生成可执行文件
我来编写一个main.c
对main.c进行编译,可以用clang或者gcc编译器都可以
$gcc -c main.c
$clang -c main.c
一旦执行编译你会发现,编译通过了,编译器只是提示一个警告
警告只是告诉main.c调用sum函数没有函数声明,那我们添加sum函数声明再次编译
perfect!编译完美通过,生成目标文件main.o
。
接着问题就来了,mian.c根本就没有sum函数定义,怎么就可以编译通过呢? 编译只是检查语法,main.c中调用sum函数并且有函数声明就没有语法问题,编译自然可以通过。
接下来你想生成可执行程序还差一步链接
的操作
$gcc main.o -o main
$clang main.o -o main
报错是因为找不到main.c中的调用sum函数
的定义,链接失败。 由此证明链接会查找该文件调用所有函数的定义
这次就完美了,可以编译器、链接一起来
$gcc main.c -o main
$clang main.c -o main
编译链接通过,输出执行结果21
C语言多文件开发
上面main.c调用了函数sum,在企业开发中是分文件开发,现在模拟一个场景。
A负责编写main.c, B负责编写Math.c(数学运算的一些函数)提供给A调用。
$ gcc -c main.c Math.c
$ gcc main.o Math.o -o app
执行程序app运行成功!
虽然A与B这样配合可以完成项目开发,但是会发现A调用B中的函数,需要去B的Math.c中找函数定义,并将在main.c中手动添加该函数的声明。这样做法是不合理的,Math.c是由B写的,B对它最熟悉的,对于调用者不需要这么麻烦,因此.h文件的作用就诞生了!
B除了编写Math.c,还要维护一个.h文件,将Math.c可以供外界调用的函数声明写在.h中。这样A在调用只需要在main.c中包含Math.h文件即可。即使以后B的Math.c中新增加了函数,A不需要修改代码,查看Math.h有这个函数声明直接调用就可以了。
.h文件作用是被其它文件包含,是不参与编译的。