收藏 分销(赏)

计算机辅修c++程序设计.doc

上传人:天**** 文档编号:2394982 上传时间:2024-05-29 格式:DOC 页数:7 大小:49.51KB 下载积分:6 金币
下载 相关 举报
计算机辅修c++程序设计.doc_第1页
第1页 / 共7页
计算机辅修c++程序设计.doc_第2页
第2页 / 共7页


点击查看更多>>
资源描述
计 算 机 辅 修 C++ 程 序 设 计 姓名: 班级: 学号: 我们编写的源程序代码为什么要预处理,编译和链接?在C++中常见的编译预处理指令有哪些? 编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并且按照操作系统对可执行文件格式的要求链接生成可执行程序。 C源程序头文件-->预编译处理(cpp)-->编译程序本身-->优化程序-->汇编程序-->链接程序-->可执行文件 1.编译预处理 读取c源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理 [析] 伪指令主要包括以下四个方面 (1)宏定义指令,如#define Name TokenString,#undef等。对于前一个伪指令,预编译所要做的是将程序中的所有Name用TokenString替换,但作为字符串常量的Name则不被替换。对于后者,则将取消对某个宏的定义,使以后该串的出现不再被替换。 (2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif,等等。这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉 (3)头文件包含指令,如#include "FileName"或者#include <FileName>等。在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。       包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在/usr/include目录下。在程序中#include它们要使用尖括号(<>)。另外开发人员也可以定义自己的头文件,这些文件一般与c源程序放在同一目录下,此时在#include中要用双引号("")。 (4)特殊符号,预编译程序可以识别一些特殊的符号。例如在源程序中出现的LINE标识将被解释为当前行号(十进制数),FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。       预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的,但内容有所不同。下一步,此输出文件将作为编译程序的输出而被翻译成为机器指令。 2.编译阶段       经过预编译得到的输出文件中,将只有常量。如数字、字符串、变量的定义,以及C语言的关键字,如main,if,else,for,while,{,},+,-,*,\,等等。预编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。 3.优化阶段       优化处理是编译系统中一项比较艰深的技术。它涉及到的问题不仅同编译技术本身有关,而且同机器的硬件环境也有很大的关系。优化一部分是对中间代码的优化。这种优化不依赖于具体的计算机。另一种优化则主要针对目标代码的生成而进行的。上图中,我们将优化阶段放在编译程序的后面,这是一种比较笼统的表示。       对于前一种优化,主要的工作是删除公共表达式、循环优化(代码外提、强度削弱、变换循环控制条件、已知量的合并等)、复写传播,以及无用赋值的删除,等等。       后一种类型的优化同机器的硬件结构密切相关,最主要的是考虑是如何充分利用机器的各个硬件寄存器存放的有关变量的值,以减少对于内存的访问次数。另外,如何根据机器硬件执行指令的特点(如流水线、RISC、CISC、VLIW等)而对指令进行一些调整使目标代码比较短,执行的效率比较高,也是一个重要的研究课题。       经过优化得到的汇编代码必须经过汇编程序的汇编转换成相应的机器指令,方可能被机器执行。 4.汇编过程       汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。 目标文件由段组成。通常一个目标文件中至少有两个段: 代码段 该段中所包含的主要是程序的指令。该段一般是可读和可执行的,但一般却不可写。 数据段 主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。 UNIX环境下主要有三种类型的目标文件: (1)可重定位文件 其中包含有适合于其它目标文件链接来创建一个可执行的或者共享的目标文件的代码和数据。 (2)共享的目标文件 这种文件存放了适合于在两种上下文里链接的代码和数据。第一种事链接程序可把它与其它可重定位文件及共享的目标文件一起处理来创建另一个目标文件;第二种是动态链接程序将它与另一个可执行文件及其它的共享目标文件结合到一起,创建一个进程映象。 (3)可执行文件 它包含了一个可以被操作系统创建一个进程来执行之的文件。 汇编程序生成的实际上是第一种类型的目标文件。对于后两种还需要其他的一些处理方能得到,这个就是链接程序的工作了。 5.链接程序 由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。 链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。 根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种: (1)静态链接在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。 (2)动态链接在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。 对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。使用动态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一些内存,因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害。 经过上述五个过程,C源程序就最终被转换成可执行文件了。缺省情况下这个可执行文件的名字被命名为a.out。 C/C++预处理指令总结  常见的预处理功能:     预处理器的主要作用就是把通过预处理的内建功能对一个资源进行等价替换,最常见的预处理有:文件包含,条件编译、布局控制和宏替换4种。     文件包含:#include 是一种最为常见的预处理,主要是做为文件的引用组合源程序正文。     条件编译:#if,#ifndef,#ifdef,#endif,#undef等也是比较常见的预处理,主要是进行编译时进行有选择的挑选,注释掉一些指定的代码,以达到版本控制、防止对文件重复包含的功能。     布局控制:#progma,这也是我们应用预处理的一个重要方面,主要功能是为编译程序提供非常规的控制流信息。     宏替换: #define,这是最常见的用法,它可以定义符号常量、函数功能、重新命名、字符串的拼接等各种功能。     下面我们看一下常见的预处理指令:     #define 宏定义     #undef 未定义宏     #include 文本包含     #ifdef 如果宏被定义就进行编译     #ifndef 如果宏未被定义就进行编译     #endif 结束编译块的控制     #if 表达式非零就对代码进行编译     #else 作为其他预处理的剩余选项进行编译     #elif 这是一种#else和#if的组合选项     #line 改变当前的行数和文件名称     #error 输出一个错误信息     #pragma 为编译程序提供非常规的控制流信息     下面我们对这些预处理进行一一的说明,考虑到宏的重要性和繁琐性,我们把它放到最后讲。     文件包含指令:     这种预处理使用方式是最为常见的,平时我们编写程序都会用到,最常见的用法是:     #include <iostream>         //标准库头文件     #include <iostream.h>         //旧式的标准库头文件     #include "IO.h"             //用户自定义的头文件     #include "……/file.h"         //UNIX下的父目录下的头文件     #include "/usr/local/file.h" //UNIX下的完整路径     #include "……\file.h"         //Dos下的父目录下的头文件     #include "\usr\local\file.h" //Dos下的完整路径     这里面有2个地方要注意:     1、我们用<iostream>还是<iostream.h>?     我们主张使用<iostream>,而不是<iostream.h>,为什么呢?我想你可能还记得我曾经给出过几点理由,这里我大致的说一下:首先,。h格式的头文件早在98年9月份就被标准委员会抛弃了,我们应该紧跟标准,以适合时代的发展。其次,iostream.h只支持窄字符集,iostream则支持窄/宽字符集。     还有,标准对iostream作了很多的改动,接口和实现都有了变化。最后,iostream组件全部放入namespace std中,防止了名字污染。     2、<io.h>和"io.h"的区别?     其实他们唯一的区别就是搜索路径不同:     对于#include <io.h> ,编译器从标准库路径开始搜索     对于#include "io.h" ,编译器从用户的工作路径开始搜索     编译控制指令:     这些指令的主要目的是进行编译时进行有选择的挑选,注释掉一些指定的代码,以达到版本控制、防止对文件重复包含的功能。     使用格式,如下: 1、#ifdef identifier     your code     #endif     如果identifier为一个定义了的符号,your code就会被编译,否则剔除 2、#ifndef identifier     your code     #endif     如果identifier为一个未定义的符号,your code就会被编译,否则剔除 3、#if expression     your code     #endif     如果expression非零,your code就会被编译,否则剔除 4、#ifdef identifier     your code1     #else     your code2     #endif     如果identifier为一个定义了的符号,your code1就会被编译,否则yourcode2就会被编译 5、#if expressin1     your code1     #elif expression2 //呵呵,elif     your code2     #else     your code3     #enif     如果epression1非零,就编译your code1,否则,如果expression2非零,就编译your code2,否则,就编译your code3     其他预编译指令     除了上面我们说的集中常用的编译指令,还有3种不太常见的编译指令:#line、#error、#pragma,我们接下来就简单的谈一下。     #line的语法如下:     #line number filename     例如:#line 30 a.h 其中,文件名a.h可以省略不写。     这条指令可以改变当前的行号和文件名,例如上面的这条预处理指令就可以改变当前的行号为30,文件名是a.h.初看起来似乎没有什么用,不过,他还是有点用的,那就是用在编译器的编写中,我们知道编译器对C++源码编译过程中会产生一些中间文件,通过这条指令,可以保证文件名是固定的,不会被这些中间文件代替,有利于进行分析。     #error语法如下:     #error info     例如:     #ifndef UNIX     #error This software requires the UNIX OS.     #endif     这条指令主要是给出错误信息,上面的这个例子就是,如果没有在UNIX环境下,就会输出This software requires the UNIX OS.然后诱发编译器终止。所以总的来说,这条指令的目的就是在程序崩溃之前能够给出一定的信息。     #pragma是非统一的,他要依靠各个编译器生产者,例如,在SUN C++编译器中:     // 把name和val的起始地址调整为8个字节的倍数     #progma align 8 (name, val)     char name[9];     double val;     //在程序执行开始,调用函数MyFunction     #progma init (MyFunction)     预定义标识符     为了处理一些有用的信息,预处理定义了一些预处理标识符,虽然各种编译器的预处理标识符不尽相同,但是他们都会处理下面的4种:     __FILE__ 正在编译的文件的名字     __LINE__ 正在编译的文件的行号     __DATE__ 编译时刻的日期字符串,例如: "25 Dec 2000"     __TIME__ 编译时刻的时间字符串,例如: "12:30:55"     例如:cout<<"The file is :"<<__FILE__"<<"! The lines is:"<<__LINE__<<endl;     预处理何去何从     如何取代#include预处理指令,我们在这里就不再一一讨论了。     C++并没有为#include提供替代形式,但是namespace提供了一种作用域机制,它能以某种方式支持组合,利用它可以改善#include的行为方式,但是我们还是无法取代#include. #progma应该算是一个可有可无的预处理指令,按照C++之父Bjarne的话说,就是:"#progma被过分的经常的用于将语言语义的变形隐藏到编译系统里,或者被用于提供带有特殊语义和笨拙语法的语言扩充。“     对于#ifdef,我们仍然束手无策,就算是我们利用if语句和常量表达式,仍然不足以替代她,因为一个if语句的正文必须在语法上正确,满足类检查,即使他处在一个绝不会被执行的分支里面。
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服