翻译环境的具体内容
在C语言中的,我们知道通过编译器运行代码可以获得一个黑窗程序,但我们却不知道这中间转换的过程是什么,下面我们就要给大家介绍一下这个转换的详细过程。 首先,我们知道一个C语言代码例如test.c,是通过翻译环境转换为可执行程序的。而这个翻译环境又是什么呢?
翻译环境: 翻译环境分为编译和链接,而编译又分为预编译,编译和汇编,所以我们就要研究一下这三个步骤对test.c干了什么,有什么作用,下面我们就对这三个步骤进行分析。
一.预编译的作用:
- 头文件展开
- 去掉注释
- 对#define定义的符号进行替换
前两条我们都可以理解,毕竟就是先将头文件中具体的内容进行展开并替换,之后将有注释的地方删除,那么第三条中的#define是什么呢?这就不得不要提出预处理的相关知识了,这个我们在下面会具体的讲解一下。
二.编译的作用 编译的具体作用就是将C代码翻译成汇编代码而在这过程中编译器做了以下这些事情:
- 语法分析
- 词法分析
- 语义分析
- 符号分析
三.汇编的作用 之前编译的过程中将C代码转换成了汇编代码并在其中对符号进行了分析,而在汇编阶段其实就是将分析好的符号进行汇总,最后形成一个符号表,以便于查找所需符号,具体为:
- 合并段表
- 符号表的合并与重定义
预处理中的宏定义与其他预处理指令
什么是宏呢? 其实宏就是一中预处理指令,是c语言标准允许在程序中用一个标识符来表示一个字符串。标识符就是宏名
宏替换:宏替换就是宏定义。在编译预处理中,将程序中所有的宏名用相应的字符串来替换,这个过程称为宏替换。
在预处理中宏分为两种,一种是无参数的,一种是有参数的 那么我们可以看出来这有参宏其实和函数有点相似啊,就是少了返回值和参数类型而已,那么我们是用函数好呢,还是用宏定义好呢? 其实两种定义方法都是有好有坏,下面具体和大家聊一下: 一. 宏相对于函数的优点
- 宏因为相对于函数来说不需要调用栈帧,也不需要进行返回,所以宏相对于函数时间开销更小,更高效
- 因为宏是没有参数类型的,所以宏可以做一些函数做不了的事。
二.宏相对于函数的缺点
- 宏不能调试,函数可以调试
- 宏不能递归,函数可以递归
- 宏由于与类型无关,所以不够严谨
- 当要实现的一个复杂的功能时候,宏可能会造成程序长度的增加,会降低可读性。
- 宏可能会由于运算符优先级而带来的问题,导致程序结果出错。
三.宏定义中的#符号与##符号
- #符号
当前#符号的作用就是将传过来的参数不进行值转换,直接取参数的名字如: 上面这代码中的#data当运行代码之后就是直接输出参数的名字。 - ##符号
此符号其实就是一个连接符号,他会将传过来的两个参数的名字进行连接,连接之后会在程序中寻找是否有与连接之后的名字相同的变量,如: 如上,当定义宏CAT之后,传参之后我们将C和H进行连接,连接之后我们得到了CH,而在程序查找我们找到了名字为CH的变量,所以此时我们输出的就是当前变量所指的值1000。
条件编译
一.#ifdef与#ifndef
-
#ifdef表示判断后面的表达式是否被定义过,如果被定义过就执行下面的语句,如果没有被定义过就不执行如: 此时表示当前__DEBUG__如果被定义了就执行printf(“hehe\n”);语句,此处的#endif和#ifdef是配对的,用来结束条件编译。 -
#ifndef和上面的#ifdef正好相反的,如果其后面的表达式没有被定义过,那么我们就执行下面的语句,如果被定义过就不执行如: 上面的代码就是表示如果没有定义__DEBUG__就执行下面的语句。
二.#if #if后面加常量表达式,如果后面的常量表达式是0的时候就跳过下面的语句,当后面的常量表达式不是0的时候就执行下面的语句。例如: 而这里得条件编译在语法方面上其实和C语言中得if判断语句是基本上一样的,所以我们可以写出以下的这种语法也是可以的: 上面的代码也和if else语句的语法是一样的,上面的代码中执行3 - 1下面的那条语句,虽然2也是满足的但是已经执行了3 - 1,所以不会执行2那条语句。
三.#if defined () 和 #if !defined()
-
#if defined(printd),此语句就是表示的是如果printd被定义了就执行下面的语句,如果没有定义就跳过该下面的语句。如: 上面的语句就是因为之前定义了print,所以就执行下面的输出语句。本质u上和#ifdef的意思是一样的。 -
#if !defined(printd),此语句就是如果printd没有被定义的时候就执行下面的语句,如果已经被定义了就跳过下面的语句,不进行执行。如: 上面的语句就是因为上面已经定义了print,所以此时就跳过下面的输出语句,本质上和#ifndef是一个意思。
|