C预编译指令 -- #define

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/itworld123/article/details/83954774
---------------------------------------------
--    2018-01-06  创建人:Ruo_Xiao
--    开发环境:VS2010
--    邮箱:[email protected]
--------------------------------------
--    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)宏函数和函数调用完全不同,前者是在预编译期,将参数记号传给了程序,后者是在程序运行期将参数的值传给了函数,即不同的过程发生在了不同的时期。
(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、预处理器的粘合剂,“##”指令
(1)将两个记号组合成一个记号
(2)例如:

#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!)

猜你喜欢

转载自blog.csdn.net/itworld123/article/details/83954774