1.程序环境
在标准C环境中,存在着一个程序环境。而程序环境又分为了翻译环境和执行环境两种。
翻译环境中源代码被转换成机器可读的指令,也就是二进制。
执行环境用于实际执行代码。
2.翻译环境
2.1 编译与链接
在这个翻译环境中,又可以分为编译和链接两大块。
2.11 编译
编译本身也分为三小部分,一是预处理,二是编译,三是汇编。
(1)预处理(预编译)
在预处理阶段中,会做出以下操作:
①注释的删除
②#include头文件的包含
③#define 符号的替换
所有的预处理指令都是在预处理阶段处理的。
(2)编译
在编译阶段中,编译器会把我们写的C语言代码翻译成汇编语言。
所以在这个阶段中,会进行语法分析、词法分析、语义分析,符号汇总。
(3)汇编
上个阶段翻译成了汇编语言,那汇编阶段该干的事就是把汇编语言翻译成机器能执行的二进制指令,并形成符号表。本文所提及的符号指的是代码中的函数,变量等等,而符号表就是各个函数的地址,通过地址来找到对应符号。
2.12 链接
在这个过程中,会将目标文件生成可执行程序。编译器进行了合并段表,符号表的合并和重定位的操作。
3.运行环境
4.预处理详解
4.1 预定义符号
__FILE__ // 进行编译的源文件__LINE__ // 文件当前的行号__DATE__ // 文件被编译的日期__TIME__ // 文件被编译的时间__STDC__ // 如果编译器遵循 ANSI C ,其值为 1 ,否则未定义
4.2 #define
#define是定义标识符。
#define name stuff
name表示要定义的符号名字,stuff表示符号名字所代表的内容。
其中stuff 可以是一个表达式,比如:
#define ADD(x,y) ((x)+(y))
注意:在写表达式的时候最好是给每个个体加上括号,以防传值时有操作符影响,前置++或者后置++等算术符。
#define的替换规则:
4.3 宏和函数的对比
宏的优点:
1.对于简单的计算,宏的执行速度更快
2.宏相比起函数,显得能更灵活,宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型,进行对应的参数替换功能。
缺点:
1.每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长。
2.临近操作符的优先级可能会使宏的调用产生与实际值不同的结果。
3.参数可能被替换到宏体中的多个位置,带有前置++或者后置++等算术符的参数可能会使结果发生改变。
4.宏不方便进行调试,因为在调试过程中是执行程序的过程,而你所看到的表面(也就是宏)可能并非是原本的模样。
5.宏不能进行递归。
函数的优点:
1.函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码。
2.函数参数只在函数调用的时候求值一次,它的结果值传递给函数。表达式的求值结果更容易预测。
3.函数参数只在传参的时候求值一次,结果更容易控制。
4.函数是可以逐语句调试的。函数是可以递归的。
缺点:
1.存在函数的调用和返回的额外开销,所以执行速度相对慢一些。不过当代码逻辑的复杂度很高时,调用和返回的时间可以忽略不计。
2.函数的参数是与类型有关的,如果参数的类型不同,就需要不同 的函数,即使他们执行的任务是 相同的。
4.4 预处理指令
这条指令用于移除一个宏定义。
#undef NAME
//如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。
1.#if 常量表达式//...#endif// 常量表达式由预处理器求值。如:#define __DEBUG__ 1#if __DEBUG__//..#endif2. 多个分支的条件编译#if 常量表达式//...#elif 常量表达式//...#else//...#endif3. 判断是否被定义#if defined(symbol)#ifdef symbol#if !defined(symbol)#ifndef symbol4. 嵌套指令#if defined(OS_UNIX)#ifdef OPTION1unix_version_option1 ();#endif#ifdef OPTION2unix_version_option2 ();#endif#elif defined(OS_MSDOS)#ifdef OPTION2msdos_version_option2 ();#endif#endif
5.如何避免头文件的重复包含
使用条件编译
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif //__TEST_H__
或者
#pragma once
就可以避免重复包含头文件。