内存模型和名称空间(单独编译)

📅 发布时间:2026/7/10 7:27:45 👁️ 浏览次数:
内存模型和名称空间(单独编译)
单独编译和C 语言一样C也允许甚至鼓励程序员将组件函数放在独立的文件中。第1 章介绍过可以单独编译这些文件然后将它们链接成可执行的程序。通常C编译器既编译程序也管理链接器。如果只修改了一个文件则可以只重新编译该文件然后将它与其他文件的编译版本链接。这使得大程序的管理更便捷。另外大多数C环境都提供了其他工具来帮助管理。例如UNIX 和Linux 系统都具有make程序可以跟踪程序依赖的文件以及这些文件的最后修改时间。运行make 时如果它检测到上次编译后修改了源文件make 将记住重新构建程序所需的步骤。大多数集成开发环境包括Embarcadero CBuilder、Microsoft Visual C、Apple Xcode 和Freescale CodeWarrior都在Project 菜单中提供了类似的工具。现在看一个简单的示例。我们不是要从中了解编译的细节这取决于实现而是要重点介绍更通用的方面如设计。例如假设程序员决定分解程序清单7.12 中的程序将支持函数放在一个独立的文件中。清单7.12将直角坐标转换为极坐标然后显示结果。不能简单地以main( )之后的虚线为界将原来的文件分为两个。问题在于main( )和其他两个函数使用了同一个结构声明因此两个文件都应包含该声明。简单地将它们输入进去无疑是自找麻烦。即使正确地复制了结构声明如果以后要作修改则必须记住对这两组声明都进行修改。简而言之将一个程序放在多个文件中将引出新的问题。谁希望出现更多的问题呢C 和C的开发人员都不希望因此他们提供了#include 来处理这种情况。与其将结构声明加入到每一个文件中不如将其放在头文件中然后在每一个源代码文件中包含该头文件。这样要修改结构声明时只需在头文件中做一次改动即可。另外也可以将函数原型放在头文件中。因此可以将原来的程序分成三部分。头文件包含结构声明和使用这些结构的函数的原型。源代码文件包含与结构有关的函数的代码。源代码文件包含调用与结构相关的函数的代码。这是一种非常有用的组织程序的策略。例如如果编写另一个程序时也需要使用这些函数则只需包含头文件并将函数文件添加到项目列表或make 列表中即可。另外这种组织方式也与OOP 方法一致。一个文件头文件包含了用户定义类型的定义另一个文件包含操纵用户定义类型的函数的代码。这两个文件组成了一个软件包可用于各种程序中。请不要将函数定义或变量声明放到头文件中。这样做对于简单的情况可能是可行的但通常会引来麻烦。例如如果在头文件包含一个函数定义然后在其他两个文件属于同一个程序中包含该头文件则同一个程序中将包含同一个函数的两个定义除非函数是内联的否则这将出错。下面列出了头文件中常包含的内容。函数原型。使用#define 或const 定义的符号常量。结构声明。类声明。模板声明。内联函数将结构声明放在头文件中是可以的因为它们不创建变量而只是在源代码文件中声明结构变量时告诉编译器如何创建该结构变量。同样模板声明不是将被编译的代码它们指示编译器如何生成与源代码中的函数调用相匹配的函数定义。被声明为const 的数据和内联函数有特殊的链接属性稍后将介绍因此可以将其放在头文件中而不会引起问题。程序清单9.1、程序清单9.2 和程序清单9.3 是将程序清单7.12 分成几个独立部分后得到的结果。注意在包含头文件时我们使用“coordin.h”而不是coodin.h。如果文件名包含在尖括号中则C编译器将在存储标准头文件的主机系统的文件系统中查找但如果文件名包含在双引号中则编译器将首先查找当前的工作目录或源代码目录或其他目录这取决于编译器。如果没有在那里找到头文件则将在标准位置查找。因此在包含自己的头文件时应使用引号而不是尖括号。图9.1 简要地说明了在UNIX 系统中将该程序组合起来的步骤。注意只需执行编译命令CC 即可其他步骤将自动完成。g和gpp 命令行编译器以及Borland C命令行编译器bcc32.exe的行为类似。AppleXcode、Embarcadero C Builderr 和Microsoft Visual C基本上执行同样的步骤但正如第1 章介绍的启动这个过程的方式不同——使用能够创建项目并将其与源代码文件关联起来的菜单。注意只需将源代码文件加入到项目中而不用加入头文件。这是因为#include 指令管理头文件。另外不要使用#include来包含源代码文件这样做将导致多重声明。警告在IDE 中不要将头文件加入到项目列表中也不要在源代码文件中使用#include 来包含其他源代码文件。#ifndef COORDIN_H_ #define COORDIN_H_ #include iostream struct polar { double distance; double angle; }; struct rect { double x; double y; }; polar rect_to_polar(rect xypos); void show_polar(polar dapos); #endif头文件管理在同一个文件中只能将同一个头文件包含一次。记住这个规则很容易但很可能在不知情的情况下将头文件包含多次。例如可能使用包含了另外一个头文件的头文件。有一种标准的C/C技术可以避免多次包含同一个头文件。它是基于预处理器编译指令#ifndef即if not defined的。下面的代码片段意味着仅当以前没有使用预处理器编译指令#define 定义名称COORDIN_H_时才处理#ifndef 和#endif 之间的语句#ifndef COORDIN_H_ ... #endif通常使用#define 语句来创建符号常量如下所示#define MAXIMUM 4096但只要将#define 用于名称就足以完成该名称的定义如下所示#inndef COORDIN_H_ #define COORDIN_H_ #endif编译器首次遇到该文件时名称COORDIN_H_没有定义我们根据include 文件名来选择名称并加上一些下划线以创建一个在其他地方不太可能被定义的名称。在这种情况下编译器将查看#ifndef 和#endif之间的内容这正是我们希望的并读取定义COORDIN_H_的一行。如果在同一个文件中遇到其他包含coordin.h 的代码编译器将知道COORDIN_H_已经被定义了从而跳到#endfi 后面的一行上。注意这种方法并不能防止编译器将文件包含两次而只是让它忽略除第一次包含之外的所有内容。大多数标准C 和C头文件都使用这种防护guarding方案。否则可能在一个文件中定义同一个结构两次这将导致编译错误。