C语言程序环境中的预处理实例分析


本篇内容介绍了“C语言程序环境中的预处理实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!整个翻译环境大致就可以画成这样一张图。下列有几点需要说明:1. 组成一个程序的每一个源文件通过编译过程分别转换成目标文件(在Linux中目标文件的后缀为.o;而在Windows中目标文件后缀为.obj)2. 每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序3. 链接器同时也会引入标准C函数库(链接库)中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中接下来介绍每一步在Linux系统下整个翻译环境的实现方法,以及每一个步骤的作用。编译可分为三个部分:(1)预处理:输入指令gcc -E test.c -o,就会将test.c文件变为test.i文件。这一步的作用是是对头文件(#include)的包含、删除注释、#define定义符号的替换等文本操作(下文会对预处理这一个步骤展开详细的介绍)(2)编译:输入指令gcc -S test.i,就会将test.i文件变为test.s文件,这一步主要作用是把C语言代码转换成汇编代码,其中包含4步:1. 语法分析;2. 词法分析;3. 语义分析;4. 符号汇总(3)汇编:输入指令gcc -c test.s,就会将test.s文件变为test.o文件,这一步是把汇编代码转换成二进制的指令,这一步是会形成符号表,此时的符号表为接下来的链接操作做出了准备多个.c文件通过编译过程后形成.o目标文件,在要执行链接的时候,输入指令gcc test.o add.o -o test,就会将.o文件变成可执行文件,这其中的操作包括合并段表和符号表的合并和重定位,这一步主要就是将多个目标文件进行连接的时候通过符号表查看来自外部的符号是否真实存在,这样就完成了整个翻译环境的操作。对于程序的执行过程可分为以下几个步骤:1. 程序必须载入内存中。在有操作系统的环境中:一般由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成2. 程序的执行开始。之后就会调用main函数3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址;程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值4. 终止程序。正在终止main函数,也有可能是意外终止的情况在C语言中,有些预处理符号是语言内置的,就比如:#define定义的标识符可以是常量、简化关键字、一些符号等,例如:对于#define定义标识符来说,如果定义的东西过长,还可以分几行来写,除最后一行外,其他每行都加上”,例如:在#define定义标识符外,#define还有一个规定,就是允许把参数替换到文本中,进而就形成了#define定义宏。声明的方式如下:这里的parament-list是由一个逗号隔开的符号表,在实际的代码中他们也会存在于stuff中。其中值得注免费云主机域名意的是:1. 参数列表的左括号必须与name相邻2. 如果parament-list与stuff两者之间有任何空白存在,参数列表就会被注释为stuff的一部分了解了#define定义宏是如何写后,接下来就是#define定义宏的替换规则:1. 在调用宏的时候,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换2. 替换文本随后被插入到程序中原来的文本位置,参数名被它们的值所替换3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程所以,总结以上规则后得出的结论就是:如果是#define定义宏用于对数值表达式进行求值的宏定义都应该加上括号,避免在使用宏时由于参数中的操作符或者邻近操作符之间不可预料的相互作用。当然,对于#define的使用还有几个注意的点:1. 宏参数和#define定义中可以出现其他#define定义的符号,但是对于宏,不能出现递归2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索对于一些想要把参数插入到字符串中的情况,我们会使用#来把一个宏参数变成对应的字符串,下面举个例子:如果是直接打印出来的话,因为字符串是可以拼接的,所以就如这样:那么,对于定义宏参数来说,就应该这样:这样字符串中的n才会根据跟着宏参数的值变化而变化。而##的作用是可以把位于它两边的符号合成一个符号。它允许宏定义从分离的文本段创建标识符。但是这样连接必须产生一个合法的标识符,否则会报错说未定义标识符。宏的优势:1. 在执行一些小型计算工作的时候,定义宏比调用函数和从函数返回的代码执行所需要的时间会更短;2. 函数的参数必须声明为特定的类型,二宏参数不用宏的劣势:1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度;2. 宏是无法进行调试的,而函数可以;3. 宏由于没有进行类型定义,所以有时候就会不够严谨;4. 宏可能会带来运算符的优先级的问题,导致程序容易出错下面列举一些编译指令:1. #undef 该指令用于移除一个宏定义2. 该指令是判断应该执行哪一个语句块3. 该指令是判断是否被定义4. 对于条件编译指令来说,其实还可以对其进行嵌套,称为嵌套指令我们在一些较大工程进行编译的时候、在多人合作同一块项目工程的时候,可能会出现头文件重复包含的情况,如果真是这样,则会导致整个代码运行时的效率大大降低,所以对头文件避免重复包含就显得十分重要了。那么,如何避免呢?下面就有一段代码可以用来避免这种情况:这段代码就可以很好地解决了头文件重复包含的问题,但是实际上,如果是在VS的环境下进行编译,会自动在最开始的地方写上:#pragma once,这句代码一样也是可以解决重复包含的问题。那么,解决完头文件重复包含的问题后,就来介绍两种头文件包含的方式:1. 用引号包含的头文件,例如:#include "test.h"。这种包含方式头文件的查找策略是先在源文件所在的目录下查找,如果该头文件未被找到,编译器就像查找库函数头文件一样在标准位置查找头文件,如果还找不到,则会直接报错。2. 用尖括号包含头文件,例如:#include 。这种包含方式则是未有第一步,直接进行第二步。但是不能说为了保证万无一失,直接把全部头文件的包含都用引号进行包含,这样的话有些时候其实是用尖括号的情况而错用引号导致程序的执行速度下降、效率下降等。“C语言程序环境中的预处理实例分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注百云主机网站,小编将为大家输出更多高质量的实用文章!

相关推荐: 微信小程序运维中心是什么

这篇文章主要为大家展示了“微信小程序运维中心是什么”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“微信小程序运维中心是什么”这篇文章吧。   “公众平台新增小程序运维中心,可方便开发者及时了解到自己小程序的运行状况。…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

Like (0)
Donate 微信扫一扫 微信扫一扫
Previous 09/07 16:56
Next 09/07 16:56

相关推荐