目录
1.什么是#define
举个例子:这里的PI就是宏的名字,3.1416就是宏的值
#define PI 3.1416//这里的PI就是宏的名字,3.1416就是宏的值
2.宏的功能:替换宏与值
① 方便检测
比如你在程序中,需要多次用到1这个值,但是值的含义又不相同,为了增加可读性,让检查代码的时候能够看到1就知道代表什么,这个时候你就可以给不同含义的1定义不同的宏的名字。
② 方便维护
如:可以用来定义数组容量 #define MAX_SIZE 100
后续使用的时候可以这样使用: int a[MAX_SIZE];
以后如果容量少了,直接修改这个宏,则使用的地方都跟着得到最新的了,就不需要一个个更改
③ 简化写法
如:可以这样的定义: #define unsigned int UINT
则后续的时候就可以这样的写了: UINT a;//与unsigned int a;等价
3. 编译器替换规则
在预处理的过程中,将所有的含有宏定义的名字替换成值
#define a 2+3
int b = 2 * a ; //这个时候就替换成了 int b = 2 * 2 + 3 ; 所以要注意多添加括号
printf ( " %s " , a is 2+3 ) ; //而这里要注意字符串常量并不会被替换,打印结果是 a is 2+3
4. 宏的一些使用细节 和 #
① 首先你要知道,字符串有自动连接的特点
char *p = " welcome_" " to_you\0 "; //_表示空格
printf(" %s " , welcome_to_you) ; //打印welcome to you
printf(" %s " , p ) ; //打印welcome to you
② #的使用
可以把宏参数编程对应的字符串,当你想让字符串里出现宏的时候就可使用。比如
***********仔细看代码**********
int i = 10 ;
#define PRINT (FORMAT , VALUE) printf("the value of "#VALUE " is " FORMAT " \n " , VALUE) ;
PRINTF("%d" ,i+3); //打印 the value of i+3 is 13
5. 两道宏的进阶题目
① 写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换。
②
offsetof
宏的实现#define offsetof(StructType, MemberName) (size_t)&(((StructType *)0)->MemberName)
StructType是结构体类型名,MemberName是成员名。具体操作方法是:
1、先将0转换为一个结构体类型的指针,相当于某个结构体的首地址是0。此时,每一个成员的偏移量就成了相对0的偏移量,这样就不需要减去首地址了。
2、对该指针用->访问其成员,并取出地址,由于结构体起始地址为0,此时成员偏移量直接相当于对0的偏移量,所以得到的值直接就是对首地址的偏移量。
3、取出该成员的地址,强转成size_t并打印,就求出了这个偏移量。