多个源代码文件
在设计大程序时,不可能将所有的代码都写在 main.c
中,一般将一个程序拆分成多个 .c
文件.可以使用下面命令将多个 .c
文件编译成一个可执行程序:
gcc main.c [xxx.c yyy.c zzz.c] [-o] [output]
如果使用ide集成开发环境,一般会有项目,编译时会将项目中的 .c
文件编译成一个可执行程序.
头文件
头文件
我们将多个 .c
文件编译成一个可执行程序时.并不是将其他.c文件插入到 main.c 的某一个部位.所以 main.c
在使用其他 .c
文件中的函数时,需要在开头声明一下函数原型.
如果不声明函数原型,但是你对函数参数的传入和结果的传出使用正确的话,也不会出现问题.但是一旦使用错误,就会出现问题.
此时就需要用到头文件了,头文件的后缀为 .h
.我们可以使用 #include
来插入一个头文件.
#include <stdlib.h>
#include "node.h"
<>
引入头文件,会在系统特定的目录找这个头文件.一般用于引入标准库的头文件.""
引入头文件,会先在当前目录寻找这个头文件,找不到时再去系统特定目录寻找,一般用于引入自己写的头文件.
头文件中一般包含了这些函数的函数原型(并不包含函数本身,如果你想也可以,但一般不这么做).在编译预处理时,编译器会把头文件插入在引入头文件的位置.这样就不用在 main.c
中声明函数原型了.
关于#include的一个误区
-
#include
不是用来引入函数库的 -
stdio.h
里只有printf
的函数原型,printf
的函数写在别的地方 -
C语言编译器会默认引入所有的标准库
-
#include<stdio.h>
只是为了让编译器知道printf
的函数原型,确保在调用时给出的参数值是正确的类型
在学这节之前,我也一直认为 #include
是引入一个函数库o(╥﹏╥)o
局部函数
如果希望一个 .c
文件中的某一个函数,只能在该 .c
中使用. 需要在函数定义的开头加 static
来修饰. 此时这个函数可以看做一个局部函数,只在他所在的 .c
文件中生效.
声明
声明有很多种, 可以使用 extern
来声明一个变量.
int i; // 变量的定义
extern int i; // 变量的声明
这个关系有点像函数的定义和函数原型的声明. 同样,如果想在 main.c
中使用一个其他 .c
文件的全局变量,就需要声明一下.
-
声明不会产生代码.
-
定义会产生代码.
头文件
- 只有声明可以写在头文件中.这是一个约定俗成的规矩,并不强制.
- 如果在头文件中写定义,可能会导致同一实体被重复定义.或者出现同名的定义.
- 某些编译器允许多个编译单元中有同名函数的存在,或者用
weak
修饰符强调这种存在.
- 某些编译器允许多个编译单元中有同名函数的存在,或者用
重复声明
- 同一个编译单元中,同名的结构不能被重复声明.
- 如果头文件中声明了一个结构,这个结构很可能会被重复声明导致程序出错.
- 我们可以用 "标准头文件结构" 来避免这种情况发生.
标准头文件结构:
/*
如果这个头文件被引用过一次,___XXX___就会被定义,下一次重复引用时,直接跳到#endif,中间的代码就不会被引用了.
*/
#ifndef __XXX__ // 如果没有定义__XXX___
#define __XXX__ // 定义___XXX___
..CODE..
#endif
这样就可以保证一个头文件只会被引用一次..