![](https://csdnimg.cn/release/download_crawler_static/2537417/bg4.jpg)
在, 并且要有所指定的类型。但是,它并不会使编译器分配贮存空
间。 而定义的做用是要求编译器分配贮存空间。当做一个声明而不
是做 定义的时候,在声明前放一个关键字“extern”。
例如,我们有一个叫“counter”的变量,如果想让它成为公用的,
我们在一个源码程序(只在一个里面)的开始定义它:“int
counter;”,再在相关的 header 档里声明它:“extern int
counter;”。
函数原型里隐含着 extern 的意思,所以不需顾虑这个问题。
c) 重复定义,重复声明,矛盾类型:
请考虑如果在一个C源码文件中 #include 两个档 a.h 和 b.h,
而 a.h 又 #include 了 b.h 档(原因是 b.h 档定义了一些 a.h
需要的类型),会发生什么事呢?这时该C源码文件 #include 了
b.h 两次。因此每一个在 b.h 中的 #define 都发生了两次,每一
个声明发生了两次,等等。理论上,因为它们是完全一样的拷贝,
所以应该不会有什么问题,但在实际应用上,这是不符合C的语法
的,可能在编译时出现错误,或至少是警告。
解决的方法是要确定每一个 header 档在任一个源码文件中只被包
含了一次。我们一般是用预处理器来达到这个目的的。当我们进入
每一个 header 档时,我们为这个 header 档 #define 一个巨集
指令。只有在这个巨集指令没有被定义的前提下,我们才真正使用
该 header 档的主体。在实际应用上,我们只要简单的把下面一段
码放在每一个 header 档的开始部分:
#ifndef FILENAME_H
#define FILENAME_H
然后把下面一行码放在最后:
#endif
用 header 档的档名(大写的)代替上面的 FILENAME_H,用底线
代替档名中的点。有些人喜欢在 #endif 加上注释来提醒他们这个
#endif 指的是什么。例如:
#endif /* #ifndef FILENAME_H */
我个人没有这个习惯,因为这其实是很明显的。当然这只是各人的
风格不同,无伤大雅。
你只需要在那些有编译错误的 header 档中加入这个技巧,但在所
有的 header 档中都加入也没什么损失,到底这是个好习惯。
1.5 重新编译一个多文件项目
清楚的区别编译和连接是很重要的。编译器使用源码文件来产生某种 形
式的目标文件(object files)。在这个过程中,外部的符号参考并 没有
被解释或替换。然后我们使用连接器来连接这些目标文件和一些 标准的
程序包再加你指定的程序包,最后连接生成一个可执行程序。 在这个阶
页码,4/16GNU make 指南 - [蓝森林-自由软件]
2005-6-26http://www.lslnet.com/linux/docs/linux-2951.htm