# define的用法

一、宏的定义与撤销
1、宏定义时尽量加上括号
#include <iostream>
#include<math.h>
using namespace std;
#define T1 3+4  //容易产生歧义
#define T2 (4+3)//添加括号后,语义清楚

int main()
{
    int a =1;
    int b =1;
    a = 2*T1;//宏替换后 int a = 2*3+4
    b = 2*T2;//宏替换后 int b = 2*(3+4)
    cout<<"a = "<<a<<endl;
    cout<<"b = "<<b<<endl;
    return 0;
}

结果如下,所以宏定义的时候,为了清楚表达语义,尽量加上括号

a = 10
b = 14
2、宏的撤销
#define PI 3.14
#undef PI
3、引导号中的宏不会被替换
#define PI 3.14
printf("%s = %f","PI",PI);//输出 PT = 3.14
4、宏定义的宏名必须是合法的标识符
#define 0X abcd //error
5、宏定义中引号必须成对出现
#define TEST1 "z //error
#define TEST2 'z //error
二、带有参数的宏定义
//带有参数的宏定义
#define MAX(a,b) (a>b?a:b)
#define MIN(a,b) (a<b?a:b)
//使用
int sum = MAX(1,2) + MIN(3,4);//替换后为: (1>2?1:2) + (3<4?3:4)
//结果是sum = 2+3 

MAX(1,2,3) //error,参数不同会报错

需要注意的是:C

(1)宏调用时参数的个数要与定义时相同。

三、跨行宏定义用反斜杠连接
//定义一个很长的宏,用反斜杠连接
#define SWAP(a,b) do{\
    int tmp = 0;\
    tmp = a;\
    a = b;\
    b = tmp;\
}while(0)

int main()
{
    int a = 3;
    int b =4;
    cout<<"a = "<<a<<" b = "<<b<<endl;
    SWAP(a,b);
    cout<<"after SWAP "<<endl;
    cout<<"a = "<<a<<" b = "<<b<<endl;
    return 0;
}

结果如下

a = 3 b = 4
after SWAP
a = 4 b = 3

从结果可以看出,宏定义是在编译阶段的代码替换,不是程序执行的函数调用。所以这里可以直接交换a和b的值。

四、三个特殊符号:# , ## , #@
#include <iostream>
#include<math.h>
#include<typeinfo>
using namespace std;
//定义一个很长的宏,用反斜杠连接
#define CONNECT(a,b) a##b
#define TOCHAR(a) #@a
#define TOSTRING(a) #a

//a##b 表示连接

int main()
{
	//a##b表示连接
	int n = CONNECT(123, 456);
	cout << "CONNECT(a,b) a##b" << endl;
	cout << n << endl;
	cout << typeid(n).name() << endl;

	const char* str = CONNECT("abcd","efg");
	cout << str << endl;
	cout << typeid(str).name() << endl;
	cout << endl;

	//#@a(参数字符化操作,将宏参数字符化,取参数中的最后一个字符,参数超过四个字符报错)
	char ch1 = TOCHAR(1);
	char ch2 = TOCHAR(123);
	cout << "TOCHAR(a) #@a" << endl;
	cout << ch1 << endl;
	cout << ch2 << endl;
	cout << endl;

	//#(字符串化操作,自动将宏参数字符串化)
	const char* ch3 = TOSTRING(123456);
	cout << "TOSTRING(a) #a" << endl;
	cout << ch3 << endl;
	system("pause");
	return 0;
}

结果如下

CONNECT(a,b) a##b
123456
int
abcdefg
char const *

TOCHAR(a) #@a
1
3

TOSTRING(a) #a
123456
请按任意键继续. . .
五、常见的宏定义
1、防止头文件被重复包含
#ifndef _BODYDEF_H_
#define _BODYDEF_H_
//头文件内容
#endif
2、得到指定地址上的一个字节值
#include<stdio.h>
#include"atlstr.h"
//B表示字节byte
#define MEM_B(x) (*( (BYTE*) (x) ) )
//B表示为int
#define MEM_I(x) (*( (int*) (x) ) )

int main()
{
	int bTest = 0x123456;

	BYTE m = MEM_B(&bTest);
	int n = MEM_I(&bTest);
	printf("%x\n", m);
	printf("%x\n", n);
	system("pause");
	return 0;
}

结果如下

56
123456
请按任意键继续. . .
3、得到一个field在结构体(struct)中的偏移量
#define OFFSETOF( type, field ) ( (size_t) &(( type *) 0)-> field )
4、得到一个结构体中field所占用的字节数
#define FSIZ( type, field ) sizeof( ((type *) 0)->field )
5、等到一个变量的地址
#define B_PTR(var) ( (byte *) (void *) &(var) ) 
#define I_PTR(var) ( (int *) (void *) &(var) )
6、将一个字母转换为大写
#define UPCASE(c) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )
7、判断字符是不是10进制的数字
#define DECCHK(c) ((c) >= '0' && (c) <= '9')
8、判断字符是不是16进制的数字
#define HEXCHK(c) (((c) >= '0' && (c) <= '9') ||((c) >= 'A' && (c) <= 'F') ||((c) >= 'a' && (c) <= 'f'))
9、防止溢出的一个方法 (判断+1之后会不会因为溢出变成最小)
#define INC_SAT(val) (val = ((val)+1 > (val)) ? (val)+1 : (val))
10、返回数组元素的个数
#define ARR_SIZE(a) ( sizeof((a)) / sizeof((a[0])) )
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值