1..数值宏常量

它可以出现在代码的任何地方,从本行宏定义开始,以后的代码就就都认识这个宏了;也可以把任何东西定义成宏。

因为编译器会在预编译的时候用真身替换替身,而在我们的代码里面却又用常常用替身来帮忙。看例子:   #define PI 3.141592654

const修饰的数据是有类型的,而define宏定义的数据没有类型。为了安全,我建议你以后在定义一些宏常数的时候用const代替,

编译器会给const修饰的只读变量做类型校验,减少错误的可能。但一定要注意const修饰的不是常量而是read only的变量

const修饰的只读变量不能用来作为定义数组的维数也不能放在case关键字后面

2.. 字符串宏常量

A),#define  ENG_PATH_1    E:\English\listen_to_this\listen_to_this_3

B),#define   ENG_PATH_2    “E:\English\listen_to_this\listen_to_this_3”

ENG_PATH_1加上双引号就成了:“ENG_PATH_1”

3.. define宏定义注释符号可以吗

#define  BSC   //       

 #define  BMC  /*    

#define  EMC  */

D),BSC my single-linecomment

E),BMC my multi-linecomment  EMC

D)和E)都错误,为什么呢?因为注释先于预处理指令被处理,当这两行被展开成//…或/*…*/时,注释已处理完毕

此时再出现//…或/*…*/自然错误.因此,试图用宏开始或结束一段注释是不行的。(上机调试可知)

 4.. define宏定义表达式

求两个数的平方#define SQR(x)  x * x

假设x的值是个表达式10+1,SQR(x)被替换后变成10+1*10+1这并不是想要得到的

怎么办括起来就好了  这样  #define SQR(x) ((x)*(x))

求两个数的和:#define SUM (x)(x)+(x)

而代码又写成这样:SUM (x)* SUM (x)。替换后变成:(5*3)+(5*3)*(5*3)+(5*3)。所以又错了!所以最外层的括号最好也别省了

要搞定宏定义表达式其实很简单,别吝啬括号就行了。

注意这一点:宏函数被调用时是以实参代换形参。而不是“值传送”

5.. 宏定义中的空格

#define SUM   (x)(x)+(x)   SUM  后边有一个空格

这还是定义的宏函数SUM(x)吗?显然不是。编译器认为这是定义了一个宏:SUM,其代表的是(x)(x)+(x)。

其关键原因还是在于SUM后面的这个空格.这个空格仅仅在定义的时候有效,在使用这个宏函数的时候,空格会被编译器忽略掉。

也就是说,定义好的宏函数SUM(x)在使用的时候在SUM和(x)之间留有空格是没问题的。比如:SUM(3)和SUM        (3)的是一样的。

 6..#undef

#undef是用来撤销宏定义的,用法如下:

#define PI 3.141592654

// code

#undef PI

//下面的代码就不能用PI了,它已经被撤销了宏定义。

也就是说宏的生命周期从#define开始到#undef结束

#define X 3

#define Y X*2

#undef X

#define X 2

int z=Y;  

z = 4.  预处理的时候 X是等于2的  X等于3已经被撤销

7..#error预处理

#error预处理指令的作用是,编译程序时,只要遇到#error就会生成一个编译错误提

示消息,并停止编译。其语法格式为:#error   error-message例:

#define ABC

 

#ifdef  ABC

#error C++ compiler required.  输出C++ compiler required.

#else

 

#endif

注意,宏串error-message不用双引号包围。遇到#error指令时,错误信息被显示,可能同时还显示编译程序作者预先定义的其他内容。

关于系统所支持的error-message信息,可以查找相关资料

8..#line预处理

#line的作用是改变当前行数和文件名称,它们是在编译程序中预先定义的标识符

命令的基本形式如下:

#line  number["filename"]

其中[]内的文件名可以省略。例如:

 #line 55 "a.h"

int main()    

{   

    printf("%d\n", __LINE__);                                 58

    printf("%s\n", __FILE__);                                  a.h

    printf("%s\n", __TIMESTAMP__);                   Fri Jun 24 10:29:00 2011

    return   0;   

}其中,文件名a.h可以省略不写。代表当前文件。。

这条指令可以改变当前的行号和文件名,例如上面的这条预处理指令就可以改变当前的行号

为55,文件名是a.h。初看起来似乎没有什么用,不过,他还是有点用的,那就是用在编译器的编写中,

我们知道编译器对C源码编译过程中会产生一些中间文件,通过这条指令,

可以保证文件名是固定的,不会被这些中间文件代替,有利于进行分析。

9.. #运算符

#也是预处理

#define  SQR(x)   printf("Thesquareof x is%d.\n",((x)*(x)));

如果这样使用宏:

SQR(8);   则输出为:   The   squareof   x   is  64.

注意,引号中的字符x被当作普通文本来处理,而不被当作一个可以被替换的语言符号。

假如你确实希望在字符串中包含宏参数,那我们就可以使用“#”,它可以把语言符号转

化为字符串。上面的例子改一改:

#define  SQR(x)   printf("The  squareof   "#x"   is%d.\n",((x)*(x)));

再使用:SQR(8);  则输出的是:  The  squareof   8   is  64.

10..##预算符

和#运算符一样,##运算符可以用于宏函数的替换部分。这个运算符把两个语言符号组

合成单个语言符号。看例子:    #define  XNAME(n)  x##n

如果这样使用宏:XNAME(8)   则会被展开成这样:  x8                   ##就是个粘合剂,将前后两部分粘合起来。

11.. 文件包含 include

文件包含是预处理的一个重要功能,它可用来把多个源文件连接成一个源文件进行编译,结果将生成一个目标文件。

C语言提供#include命令来实现文件包含的操作,它实际是 宏替换的延伸,有两种格式:

1:  #include<filename>

其中,filename为要包含的文件名称,用尖括号括起来,也称为头文件,表示预处理到系统规定的路径中去获得这个文件

(即C编译系统所提供的并存放在指定的子目录下的头文件)。找到文件后,用文件内容替换该语句。

2:  #include“filename”

其中,filename为要包含的文件名称。双引号表示预处理应在当前目录中查找文件名为ilename的文件,若没有找到,

则按系统指定的路径信息,搜索其他目录。找到文件后,用文件内容替换该语句。

需要强调的一点是:#include是将已存在文件的内容嵌入到当前文件中。

另外关于#include的路径也有点要说明:include支持相对路径,格式如trackant(蚁迹寻踪)所写:  .代表当前目录,..代表上层目录。