---------------------------------------------
-- 2018-01-06 创建人:Ruo_Xiao
-- 开发环境:VS2010
-- 邮箱:xclsoftware@163.com
--------------------------------------
-- 2018-01-07 修改人:Ruo_Xiao
-- 添加#undef指令
---------------------------------------------
一、概括
1. 将一些文本替换成另外一些文本。
2. 以“#”开始,第一个换行符为止。可以出现在源文件任何位置。
3. 有效范围:从指令出现的地方到该文件末尾或者该符号对应的 #undef。
4. ANSI 之后,允许预编译指令的“#”前面添加空格和制表符,“#”和指令的其余部分之间亦可有空格。但是,之前是不允许的(K&R C)。
5. 常用的预编译指令:
#define、#undef、#include、#ifdef、#else、#endif、#ifndef、#if、#elif、#line、#error和#pragma 。
二、符号常量:#define
#define PI 3.1415926
#define Add(x,y) ((x)+(y))
//预编译指令 宏 替换体(替换列表)
//X和Y被成为宏参数。
//注意:上述例子中每一个括号都是不可缺少的。
1、作用:一旦预处理器在程序中找到该宏,就会用替换体替换该宏。
2、宏变成最终替换文本的过程被称为宏展开。
3、宏可以表示任何字符串(数值、函数、字符串)和其他宏。
4、注意:宏如果在双引号里面,预处理是不会进行文本替换的。
5、不带参数的宏
(1)如上图中定义的“PI”。
(2)有的编译器将宏的替换体看作是记号型字符串,而不是传统意义上的字符型字符串。C预处理器记号是宏定义的替换体中单独的“词”,用空格把这些词分开。
例如:
#define TWO 1*2
上述的宏的替换体的记号为“1*2”,如果改成下例:
#define TWO 1 * 2
则记号就有三个,分别是“1”、“*”和“2”。
小结:宏的替换体解释为字符型字符串,则将空格作为替换体的一部分。解释为记号型字符串,则把空格作为替换体中各记号的分隔符。
(3)重定义常量
同一文件中,同一符号被定义了两次以上,这个过程被称为重定义常量。例如:
#define PI 3.1415
#define PI 3.1415926
这种情况下,有的编译器报错,有的编译器警告,有的编译器没有任何提示信息(VS2010),以最后一个符号定义为准。
例如:
#define x 9
#define x 10
int iSum[x];
这里 iSum 中元素有 10 个。
6、带参数的宏
(1)宏中使用参数的外形和函数很像的被称为类函数宏。
(2)宏函数和函数调用完全不同,前者是在预编译期,将参数记号传给了程序,后者是在程序运行期将参数的值传给了函数,即不同的过程发生在了不同的时期。
应用:
Z = Add(3,7);
7、用宏参数创建字符串:#运算符
(1)一般的宏在字符串中都会被视为普通的文本,但是允许在宏替换中的字符串中包含宏参数。“#x”就可转换为字符串“x”的形参名,这个过程被称为字符串化(注意使用“”)。
(2)例如:
#include "stdafx.h"
#include <stdio.h>
#define POST(x) printf("I am "#x",%d\n",((x)*(x)))
int _tmain(int argc, _TCHAR* argv[])
{
POST(10);
POST(2 + 3);
getchar();
return 0;
}
结果:
8、预处理器的粘合剂,“##”指令,将两个记号组合成一个记号。
例如:
#include "stdafx.h"
#include <stdio.h>
#define XNAME(n) iX##n
#define Print_Xn(n) printf("iX"#n" = %d\n",iX##n)
int _tmain(int argc, _TCHAR* argv[])
{
int XNAME(1) = 2; //相当于:int iX1 = 2
int XNAME(2) = 5; //相当于:int iX2 = 5
Print_Xn(1);
Print_Xn(2);
getchar();
return 0;
}
结果:
9、变参宏
(1)指令如下:
"..." 和 "__VA_ARGS__"
这两个指令组合可以让用户定义可变参数的类函数宏。
(2)例如:
#include "stdafx.h"
#include <stdio.h>
#define Print_X(x,...) printf("x = "#x","__VA_ARGS__)
int _tmain(int argc, _TCHAR* argv[])
{
int x = 11;
int y = x*x;
Print_X(x,"y = %d\n",y);
getchar();
return 0;
}
结果:
10、宏函数和普通函数的对比
(1)宏定义只能写在一行,虽然编译器没有硬性规定,但是请遵守这条约定。
(2)空间:使用宏函数20个地方,就会有20个副本,但是函数只有一个。
(3)时间:宏函数没有函数跳转,节省时间。如果嵌套调用,效果很明显。
(4)宏不用考虑形参的数据类型,因为在宏眼里,一切都是字符串或者记号。
三、#undef
1. 取消之前的 #define 定义。
2. 即使之前没有被定义,直接使用此指令也是没有问题的。所以在使用某个符号时,若不确定之前是否已使用,可以在前面加上#undef。
四、拓展
字符常量和符号常量的区别
(1)字符常量:直接在代码中书写的数值,例如:5.78、3.1415、7。
(2)符号常量:用一个标识符代替一个常量。先定义后使用,例如:#define PI 3.1415926
(SAW:Game Over!)