一、宏定义:
#define命令进行宏定义,他将一个标示符定义为一个字符串,标示符称为宏名,字符串称为替代文本;
#define命令有两种格式:简单的宏定义和带有参数的宏定义
1、简单的宏定义:
#define <宏名> <字符串>如:#define PI 3.14
2、带有参数的宏定义
#define <宏名>(<参数表>) <宏体> 如:#define A(x) x
在程序被编译之前,先将宏名用被定义的字符串替换,称为宏替换,替换后才进行编译。
二、宏替换的时机:
源程序处理过程:预处理---编译----汇编---链接,其中宏替换就是在预处理的过程中进行的
1)文件包含:可以把源程序中的#include扩展为文件正文,即把头文件找到并展开到#include所在处;
2)条件编译:预处理器根据#if或#ifdef等编译命令及其后的条件将源程序中的某部分包含进来或排除在外,通常把排除在外的语句换成空行;
3)宏展开:预处理器将源程序中出现的对宏的引用展开成相应的宏定义
经过预处理的源程序和原来的源程序有所不同,但是这个阶段所进行的工作只是纯粹的展开和替换,没有任何计算工作
三、#define常见问题
1)简单的宏定义中出现的问题:
代码如下:
- 例1:
- #define N 2+2
- void main()
- {
- int a=N*N;
- printf(“%d”,a);
- }
- 输出为8,不为16
- 分析:其中N代表的是2+2,一般同学在读到这个程序时,会反应成N=2+2=4,然后a的输出为16,这是错误的,答案应该是8,原因是宏替换是发生在预处理阶段,这个阶段只进行简单的替换,而不会有计算的功能,所以N代表的是字符串2+2而不是4,那么a=2+2*2+2,按照运算符的优先级,应该=8,而不是4*4=16.
- 如果想达到16这个结果,可以改正一下源程序#define N (2+2),这样的话,结果就会是16.
-
- 2)带参数的宏定义出现的问题
- 以求平方的函数为例:
- 一般同学会这样写:
-
- #define area(x) x*x
- /*这在使用中是很容易出现问题的,看如下的程序*/
-
- void main()
- {
- int y = area(2+2);
- printf(“%d”,y);
- }
- 输出结果为8,不为16,原因如上面所说,把参数x用2+2替换,那么y=2+2*2+2=8
- 所以好的编程喜欢是这样的:#define area(x) (x)*(x)
- 如果y=area(2+2)/area(2+2),一般人一看分子分母相同,觉得会是1,那就错了,我们分解一下:
y=(2+2)*(2+2)/(2+2)*(2+2)=4*4/4*4=16,所以更好的编程习惯是这样的:#define area(x) ((x)*(x)),这个非常有必要所以如果是自己编程使用宏替换,则在使用简单宏定义时,当字符串中不只一个符号时,加上括号表现出优先级,如果是带参数的宏定义,则要给宏体中的每个参数加上括号,并在整个宏体上再加一个括号
四、#define中的三个特殊符号:##、#、#@1)##表示连接,如#define Conn(x,y) x##y
- int n = Conn(123,456); /* 结果就是n=123456;*/
- char* str = Conn("asdf", "adf"); /*结果就是 str = "asdfadf";*/
- 2)#@表示给结果加上一个单引号,返回一个const char类型,如:
- #define ToChar(x) #@x
- char a = ToChar(1);结果就是a='1'
- 如果参数超过四个字符,就会报错
- 3)#表示给结果加上一个双引号,返回一个char* 类型,如:
- #define ToString(x) #x
- char* str = ToString(123132);就成了str="123132"
- 五、常用的宏定义
- 1)防止头文件被重复包含
- #ifndef HELLO_H
- #define HELLO_H
- ....(此处包含头文件)
- #endif
- 2)得到指定地址上的一个字节或一个字
-
- #define MEM_B( x ) ( *( (byte *) (x) ) )
- #define MEM_W( x ) ( *( (word *) (x) ) )
- #include <iostream>
- #include <windows.h>
-
- #define MEM_B(x) (*((byte*)(x)))
- #define MEM_W(x) (*((WORD*)(x)))
-
- int main()
- {
- int bTest = 0x123456;
-
- byte m = MEM_B((&bTest));/*m=0x56*/
- int n = MEM_W((&bTest));/*n=0x3456*/
-
- return 0;
- }
- #define MEM_B( x ) ( *( (byte *) (x) ) )
- __LINE__ 对应%d,注意前后都是双下划线,表示__LINE__所在的行号
- __FILE__ 对应%s,源文件的文件路径
- __DATE__ 对应%s,日期
- __TIME__ 对应%s,时间
- 如:
- 1// test_base1.cpp : Defines the entry point for the console application.
2#include "stdafx.h"
3#include "stdio.h"
4#line 50
5int main(int argc, char* argv[])
6{
7 int n;
8 int line = __LINE__; //注意前后都是双下划线
9 char file[] = __FILE__;
10 char date[] = __DATE__;
11 char time[] = __TIME__;
12 printf("line=%d\n,file=%s\n,date=%s\n,time=%s\n",line,file,date,time);
13 return 0;
14}
- 如果没有#line 50,那么输出的结果为
-
- 如果有#line 50,输出结果为:
-
- #line 50表示,#line 50的下一行为第50行
-
- #define area(x) x*x
-