C程序设计语言(李雁妮)第8章.ppt
- 文档编号:1772084
- 上传时间:2022-10-24
- 格式:PPT
- 页数:51
- 大小:404KB
C程序设计语言(李雁妮)第8章.ppt
《C程序设计语言(李雁妮)第8章.ppt》由会员分享,可在线阅读,更多相关《C程序设计语言(李雁妮)第8章.ppt(51页珍藏版)》请在冰豆网上搜索。
第8章源文件和程序第8章源文件和程序8.1分别编译8.2链接8.3头文件的有效使用8.4命令行参数8.5程序小结练习题第8章源文件和程序本章要点:
本章要点:
程序源文件的分别编译;程序的链接;使用头文件的作用与意义;主程序和命令行参数;程序的结构、初始化和终止。
在详细讲述本章的内容之前,让我们首先看一下一个C+源程序的处理过程,以此了解程序编译、处理过程中的一些基本概念及术语。
第8章源文件和程序一个C+源程序的处理过程如图8.1所示,步骤如下:
(1)当用户将一个C+源程序(C+源程序的后缀名为.cpp,假定某一源文件名为myprog.cpp)提交给编译器(Compiler,假定环境为VC6.0)时,编译器首先对C+源程序进行预处理(Preprocess),即将程序中的#include指令中的头文件内容全部包含进该源文件中。
经预处理后得到的结果(文件名为myprog.i)称为编译单元(TranslationUnit)。
每个编译单元才是编译器将要真正施加编译和C+的各种语法规则所能作用之处。
每个编译单元文件是一个临时文件,它只对编译器可见。
第8章源文件和程序
(2)编译器对所产生的编译单元进行编译,产生目标文件(myprog.obj)。
(3)链接器(Linker,有时亦称为装载器Loder)将目标文件及源程序所需的库资源(如库中的类)进行链接。
(4)产生源文件的可执行文件(myprog.exe)。
第8章源文件和程序图8.1C+源程序的处理过程第8章源文件和程序如果一个程序由多个源文件构成,则链接器的作用除了链接库外,还将多个分别编译的源文件绑定/链接在一起,并对其中的各种定义(如变量、类、函数等定义)做一致性检查。
链接分为静态链接和动态链接两种。
静态链接指在程序运行前便完成了链接任务;动态链接指程序运行时可链接一些新的东西,如动态链接库DLL文件等。
第8章源文件和程序8.1分分别别编编译译在文件系统中,一个文件既是存储的基本单元,亦是传统的编译单元,但将一个实用的C+源程序存储在一个文件中通常是不可能的。
一个实用的程序往往由多个源文件构成。
这是因为:
(1)实用的程序一般需要多个程序员分工合作开发,多个人同时对同一个源程序文件进行编辑是不实际的且易于造成版本的混乱。
(2)实用程序应利用多个源程序文件(程序的物理结构(PhysicalStructure)来强调程序的逻辑结构(LogicalStructure)。
第8章源文件和程序(3)编译程序的基本处理单元是源程序文件,其编译开销(即所需的编译时间和所占用的内存空间)与源程序文件的大小相关。
因此,为了节省编译开销,常常需要将程序组织成多个源文件。
(4)对于有一定规模的程序,应当尽量避免小范围的修改引起大范围的重新编译。
因此,将程序以多个源文件进行组织可避免此问题。
因此,我们应将一个实用的C+源程序划分成多个源文件,并分别实施编译。
然而,对一个源程序各文件实施分别编译是有条件的,即:
(1)编译程序应具有分别编译的能力。
第8章源文件和程序
(2)在该源程序各文件中出现的任何符号名,程序员都在程序中给出了定义声明、非定义声明或者声明的来源。
如下段代码main函数对printf和prompt的引用都应预先声明后才能正确进行编译:
extern“C”intprintf(constchar*,.);/对C库函数printf的声明char*prompt=“Helloworld!
n”;/对prompt的定义声明intmain()printf(prompt);return0;第8章源文件和程序8.2链链接接8.2.1链接与一致性的基本概念链接与一致性的基本概念所谓链接,即将C+程序的各个源文件绑定在一起,并进行程序中各源文件的一致性检查。
若一个C+程序由多个源文件构成,又各自进行了分别编译,则链接器在链接它们时将对各源文件中声明(定义声明或非定义声明)的每一个标识符(函数名、类名、名字空间名、变量名、模板名、枚举类型名、枚举符等)做跨越整个C+程序各文件编译单元的一致性检查,除非它们被显式地描述为是局部的。
第8章源文件和程序因此,为了进行一个C+程序各编译单元的成功链接,程序员的任务是:
(1)保证在各编译单元中使用的标识符都进行了声明。
(2)各编译单元的声明(定义声明和非定义声明)具有一致性。
(3)上述标识符保证在各编译单元中仅定义声明了一次,在各编译单元中可非定义声明多次,但各编译单元中的声明必须保证类型的完全一致。
第8章源文件和程序如果一个名字可以用在并非其定义的编译单元中,则称该名字具有外部链接(ExternalLinkage)性,即该名字的作用域在定义的编译单元和其它的编译单元中。
与之相反,若一个名字仅能用于它所定义的编译单元中,则称该名字具有内部链接(InternalLinkage)性。
具有内部链接性的名字有:
由const和typedef所定义的名字;未命名的名字空间;static变量名;inline函数名。
第8章源文件和程序即上述类别的名字具有局部性(局部于特定编译单元)。
若一个源程序由多个文件组成,各文件又进行了分别编译,在链接时保证其各编译单元中所有声明的一致性的具体含义是:
(1)在不同的编译单元中出现的同一全局名字,其定义声明和非定义声明要有一致的类型。
(2)在不同的编译单元中出现的同一全局变量或函数,在且仅在一个编译单元中有定义,其它编译单元均应做“extern”声明。
例1一个源程序由file1和file2构成,若在file1中定义声明了变量名x和函数名f:
第8章源文件和程序file1.cpp:
intx=1;intf()/*.*/则在file2中,我们必须对x和f做非定义声明:
file2.cpp:
externintx;externintf();例例2一个源程序由file3和file4构成,若在两文件中做了以下声明(定义声明或非定义声明):
file3.cpp:
第8章源文件和程序intx=1;/定义声明intb=1;/定义声明externintc;/非定义声明file4.cpp:
intx;/定义声明externdoubleb;/非定义声明externintc;/非定义声明则程序链接时将报错如下:
x在两个编译单元中定义声明了两次;b在定义声明和非定义声明中的类型不一致;c只有非定义声明而没有定义声明。
第8章源文件和程序(3)在不同编译单元中出现的同一自定义类型是一致的。
例例3下述C+程序的两个源文件(file1和file2)中所声明的两个自定义类型不一致。
第8章源文件和程序保证各编译单元自定义类型一致的有效办法是使得每一个类型仅在一个源文件中定义。
通常采用头文件(HeaderFiles)机制以实现这一目标,即将各种自定义类型写入到特定的头文件中,然后再利用#include指令将其包含到使用该自定义类型的各文件中。
第8章源文件和程序8.2.2头文件头文件头文件(Header)是一种特殊的文件,它是共享性信息的承载体,以便在不同的物理程序文件之间维护某种一致性的关系(具体示例见后续内容)。
头文件分为两类:
标准库头文件和用户自定义头文件。
标准库头文件是标准库提供的一组头文件,标准库的功能亦由这一组标准头文件给出。
如C标准库头文件math.h、stdio.h(与之对应的C+标准头文件是cmath和cstdio)等。
用户自定义头文件就是用户自己定义的头文件,其中用户存放了一些供一个C+程序各源文件共享的信息等。
第8章源文件和程序8.2.3#include指令指令#include指令是一条预处理指令,该指令由运行环境中的预处理器进行识别与处理。
#include指令具有以下两种形式:
#include#include“头文件名”这两种形式的功能是一样的:
用查找到的头文件的一份副本取代这条预处理指令,即把查找到的指定的头文件内容包含到源文件中。
两者的唯一差别是查找头文件的路径不同。
前者在系统指定的路径下查找;而后者首先在该源文件所在的路径下查找,若找不到,则再到系统路径下查找。
第8章源文件和程序因此,我们应采用第一种形式来包含系统标准库头文件,而用第二种形式来包含用户自定义的头文件(假定用户头文件和其源文件放在同一目录下)。
第8章源文件和程序8.2.4用户头文件内容的设计用户头文件内容的设计从上述的讲述中知,对一个实用的、具有一定规模的程序而言,我们应将其逻辑划分成若干个源文件,并将各源文件中共享的信息存放到一个或多个头文件中,以确保分别编译和正确链接。
例如,为了确保8.2.1小节例3中文件file1和file2中自定义类型的一致性,我们应将file1和file2文件中所用到的自定义类型的定义存储在某个自定义头文件中(假设为myheader1.h),然后在file1和file2中分别包含它们。
示例代码如下:
第8章源文件和程序第8章源文件和程序如上所述,为了保证正确链接,必须遵循8.2.1节所陈述的各种原则,因此,作为首要原则,我们在设计一个头文件时(库头文件/用户自定义头文件),其中只应包含表8.1所示的内容,只有这样,才能保证在头文件中声明的实体在跨各编译单元中仅定义了一次,并且其定义声明和非定义声明的同一实体的类型保证一致。
第8章源文件和程序第8章源文件和程序永远不能将表8.2所示的内容放入到头文件中。
第8章源文件和程序特别重要的是,在各编译单元中一定要保证一次定义原则(One-DefinitionRule,ODR)。
ODR的准确含义是:
(1)每个实体在各编译单元中仅定义了一次;
(2)每个实体在不同的编译单元中被定义了多次,但它们是单词对单词(token-token)的完全相同;它们所指的是同一实体且含义相同。
因此,下述代码片断中的定义就符合一次定义原则:
/file1.cppstructSinta;charb;voidf(*S);第8章源文件和程序/file2.cppstructSinta;charb;voidf(*Sp)/*/;/编译器忽略形参参数名而下述代码片断中的定义就不符合一次定义原则:
例例4/file1.cppstructS1inta;charb;/file2.cstructS1inta;charbb;/两个S1非token-token一致例例5/file1.cpp第8章源文件和程序typedefintX;/X是int的别名structS2Xa;charb;/file2.cpptypedefcharX;/X是char的别名structS2Xa;charb;/两个S2成员的类型不一致C+程序与C函数(或其它语言)链接是十分常见的。
由于C+函数与C函数(或其它语言)的编译处理不同(函数的参数表等处理规则不同),因此,必须对所链接的C函数(或其它语言)进行特别的声明。
例如声明:
第8章源文件和程序extern“C”char*strcpy(char*,constchar*);extern“C”intprintf(constchar*,.);intstrlen(constchar*);中的externC(在某一平台上)即是通知链接器以C的方式进行链接。
第8章源文件和程序8.3头文件的有效使用头文件的有效使用为了有效地实现编译(或分别编译)和正确链接,必须使用头文件机制,但头文件内容的组织及其所采用的#include指令必须恰当,否则,仍然会造成链接失败。
一般,一个头文件内容的组织策略有两种:
(1)将应当在头文件中出现的定义放在同一个头文件中。
(2)为程序的每一个逻辑单元设立一个对应的头文件。
第一种策略仅适合于程序规模较小并且无分别编译的情况。
实际应用中我们常采用第二种策略。
第8章源文件和程序采用第二种策略的动力之一是每一个头文件都可以独立地起作用,这样的头文件本身自然被尽可能地完整化。
但这样又有可能出现同一个源程序文件多次地包含了同一个头文件,从而造成同一个类型被
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 程序设计语言 李雁妮
![提示](https://static.bdocx.com/images/bang_tan.gif)