C/Cpp / #define

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值