原创文章,转载请注明出处:http://blog.csdn.net/yanghaoran321/article/details/7662131
1、编译一个C程序的第一个步骤就是预处理,它的主要任务是包括删除注释,插入被#include指令包含的文件的内容、定义、替换由#define指令定义的符号以及确定代码的部分内容是否应该根据一些条件编译指令进行编译;
预处理器符号:
(1)__FILE__ 进行编译的源文件名;
(2)__LINE__ 文件当前行的行号;
(3)__DATE__ 文件被编译的日期;
(4)__TIME__ 文件被编译的时间;
(5)__STDC__ 如果编译器遵循ANSI C,其值为1,否则未定义;
2、#define的基本用法:
#define name stuff
使用#define指令,可以把任何文本替换到程序中;(如果定义中的stuff非常长,可以分成几行,除了最后一行外,每行的末尾都要加一个反斜杠);
3、宏的声明方式:
#define name(parameter-list) stuff
注:parameter-list是一个由逗号分隔的符号列表,参数列表的左括号必须与name紧邻,否则参数列表会解释为stuff的一部分;
所有用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时,由于参赛中的操作符或邻近的操作符之间不可预料的相互作用;
4、#define定义符号和宏的三个步骤:
(1)在调用宏时,首先对参数进行检查,看看是否包含了任何由#define定义的符号,如果是,它们首先替换;
(2)替换文本随后被插入到程序中原来文本的位置,对于宏,参数名被它们的值所替代;
(3)最后,再次对结果文本进行扫描,看看它是否包含了任何由#define定义的符号,如果是就重复上述处理过程;
在这个过程中,应注意以下问题:
(1)宏参数和#define定义的可以包含其他#define定义的符号,但是宏不可以出现递归;
(2)当预处理器搜索#define定义的符号时,字符串常量的内容并不进行检查;
5、宏参数插入到字符常量中的两个技巧:
(1)只有当字符串常量作为宏参数给出时才能使用
#define PRINT(FORMAT, VALUE) \
printf("The value is "FORMAT"\n", VALUE)
....
PRINT("%d", x + 3);
(2)使用预处理把一个宏参数转化为一个字符串(#argument被预处理器翻译为“argument”)
#define PRINT(FORMAT, VALUE) \
printf("The value of "#VALUE" is "FORMAT"\n", VALUE)
....
PRINT("%d", x + 3);
将输出:The value of x + 3 is 25
6、##结构作用是将位于它两边的符号连接成一个符号(允许宏定义从分离的文本片段创建标识符)
#define ADD_TO_SUM(sum_number, value) \
sum ## sum_number += value
....
ADD_TO_SUM(5, 25);
产生的结果是将25的加到sum5中(这种连接必须产生一个合法的标识符,否则结果是未定义的);
7、宏经常应用于执行简单的计算,至于为何不用函数来完成一些简单的运算,有以下两个原因:
(1)用于调用和从函数返回的代码有可能比实际执行这个小型计算工作的代码更大,因此使用宏比使用函数在程序的规模和速度方面都更胜一筹;
(2)函数的参数必须声明为一个特定的类型,但是宏是与类型无关的;
但是宏也有其不利之处:使用宏会增加程序的长度,并且使用具有副作用的参数可能在宏的使用过程中产生不可预料的结果;
8、宏和函数的不同之处:
9、#undef用于移除一个宏定义;
10、条件编译可以用于调试程序和在编译时选择不同的代码部分
#if constant-expression
statement
#elif constant-expression
other statement
#else
other statement
#endif
11、编译器支持两种不同类型的文件包含:函数库文件和本地文件;
#include <filename>
#include "filename"
前者编译器是在编译器定义的“一系列标准位置”查找函数库头文件;
后者编译器是源文件所在的当前目录下进行查找;
12、可以使用条件编译的方法来解决多重包含的问题
#ifndef _HEADERNAME_H
#define _HEADERNAME_H 1
/*
**ALL the stuff that you want in the header file
*/
#endif
用上述的方法就可以很好的消除多重包含的危险;