程序的编译

CC++是强类型语言,变量类型均应在代码执行前确定。
函数声明方面C和C++则不同, 对于函数在被调用之前未声明或定义:

  1. C++是不允许的
  2. C是允许的, 默认作为隐式声明处理,只要在调用函数之后定义,或在别的模块中定义并编译成库文件,该库文件在调用函数所属模块编译时载入,程序即可正常运行。

初看起来C语言这一特性是灵活、省事,但缺点是:

  1. 程序可读性差
  2. 易出错: 数先声明再调用,是一种纠错机制,如果不声明,则没有用到这种纠错机制,虽然编译、连接通过,程序也能运行,但很可能结果不正确。

使用头文件编译

源文件及内容如下, 均在同一目录下:

1
2
3
// a.h

int funcA(int a);
1
2
3
4
5
6
7
8
9
10
// a.c

#include "a.h"

int funcA(int a) {
if (a > 10)
return 10;
else
return a;
}
1
2
3
// b.h

int funcB(int b);
1
2
3
4
5
6
7
8
// b.c

#include "b.h"
#include "a.h"

int funcB(int b) {
return 4 / funcA(b);
}
1
2
3
4
5
6
7
// main.c

#include "b.h"

int main() {
funcB(2);
}

使用头文件可以保证在使用前就对变量和函数进行了声明。

Makefile:

1
2
main: a.c b.c main.c
gcc -o main a.c b.c main.c

没有警告,编译通过:

1
2
$ make
gcc -o main a.c b.c main.c

不使用头文件编译

源文件及内容如下, 均在同一目录下:

1
2
3
4
5
6
7
8
// a.c

int funcA(int a) {
if (a > 10)
return 10;
else
return a;
}
1
2
3
4
5
// b.c

int funcB(int b) {
return 4 / funcA(b);
}
1
2
3
4
5
// main.c

int main() {
funcB(2);
}

Makefile:

1
2
main: a.c b.c main.c
gcc -o main a.c b.c main.c

会警告函数在使用前没声明,但是不报错,编译可通过:

1
2
3
4
5
6
7
8
9
10
$ make
gcc -o main a.c b.c main.c
b.c: In function ‘bar’:
b.c:3:2: warning: implicit declaration of function ‘foo’ [-Wimplicit-function-declaration]
foo(m, x);
^~~
main.c: In function ‘main’:
main.c:2:2: warning: implicit declaration of function ‘bar’ [-Wimplicit-function-declaration]
bar(6);
^~~