C语⾔define⾼级⽤法⼤全
今天在看代码时,突然发现很多define的⽤法看不懂,故在此总结⼀下,顺便吐槽⼀下,C语⾔的宏复杂起来真的很难看懂。不信的去看下这个的源码:
⼀、宏的定义与撤销
需要注意的是:
(1)宏定义应注意添加括号,这样语义会⽐较清晰。
(2)使⽤#undef可以撤销宏定义。
(3)引号中的宏定义不会被替换。
(4)宏定义的宏名必须是合法的标识符。
(5)宏定义中单、双引号必须成对出现。
⼆、带有参数的宏定义
需要注意的是:
(1)宏调⽤时参数的个数要与定义时相同。
三、跨⾏的宏定义,使⽤反斜杠 分隔
这种跨⾏的代码就是函数宏的感觉了。#include"stdio.h"
#define test(x,y)do\
{\
int a = x;\
int b = y;\
printf("%d",a);\
}while(0);\
int a = x + y;
int main(){
test(1,2);
printf("%d",a);
}
四、三个特殊符号:****#,##,#@
五、常见的宏定义
1、防⽌头⽂件被重复包含
2、得到指定地址上的⼀个字节值或字值
3、得到⼀个field在结构体(struct)中的偏移量
#define OFFSETOF( type, field )((size_t)&(( type *) 0)-> field )
4、*得到⼀个结构体中field所占⽤的字节数
#define FSIZ( type, field )sizeof(((type *) 0)->field )
5、得到⼀个变量的地址(word宽度)
#define B_PTR(var)((byte *)(void*)&(var))
#define W_PTR(var)((word *)(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、防⽌溢出的⼀个⽅法
#define INC_SAT(val)(val =((val)+1 >(val))?(val)+1 :(val))
10、返回数组元素的个数
#define ARR_SIZE(a)(sizeof((a))/sizeof((a[0])))
--------------短⼩结论----------------------
涉及到宏定义展开顺序的知识,如果宏替换以# ##为前缀 ,则由外向内展开
#define f(x) #x //结果将被扩展为由实际参数替换该参数的带引号的字符串
#define b(x) a##x //连接实际参数
#define ac hello
int main(void)
{
f(b(c))//display "b(c)"
}
1234567
如果最外层p(x)宏替换不以# ##为前缀,则由内向外展开
#define p(x)f(x)
#define b(x) a##x
#define ac hello
int main(void)
{
p(b(c))// display "hello"
fprintf作用
return0;
}
123456789
问题:下⾯通过宏定义实现⼀个可以指定前缀的字符串。
PREFIX+".%d"
⽅法1:使⽤#运算符。出现在宏定义中的#运算符把跟在其后的参数转换成⼀个字符串。有时把这种⽤法的#称为字符串化运算符。
#include<cstdio>
#define PREX 1.3.6
#define FORMAT(n) #n".%d\n"
int main()
{
int ival =246;
printf(FORMAT(PREX), ival);// PREX.246
return0;
}
12345678910
但是输出结果是:PREX.246,和预期的结果不⼀样,宏PREX作为宏FORMAT的参数并没有替换。那么如何让FORMAT宏的参数可以替换呢?
⾸先,C语⾔的宏是允许嵌套的,其嵌套后,⼀般的展开规律像函数的参数⼀样:先展开参数,再分析函数,即由内向外展开。但是,注意:
(1) 当宏中有#运算符时,参数不再被展开;
(2) 当宏中有##运算符时,则先展开函数,再展开⾥⾯的参数;
PS: ##运算符⽤于把参数连接到⼀起。预处理程序把出现在##两侧的参数合并成⼀个符号(⾮字符串)
⽅法2:修改宏定义的格式,再添加⼀个中间宏TMP(x)实现对参数的替换,然后再替换为最终想要的字符串。
#define PREX 1.3.6
#define FORMAT(x)TMP(x)
#define TMP(x) #x".%d\n"
int main()
{
int ival =246;
printf(FORMAT(PREX), ival);// 1.3.6.246
return0;
}
12345678910
嵌套宏在某些情况下还是有⼀定的⽤处,但是我可能更愿意定义⼀个函数宏来完成上⾯这个⼯作:
#define FORMAT_FUN(szPrex, szFormat)do{\
char szTmp[128]={0};\
_snprintf(szTmp,sizeof(szTmp)-1,"%s", szFormat);\
_snprintf(szFormat,sizeof(szFormat)-1,"%s%s", szPrex, szTmp);\
}while(0);\
const char*szPrex ="1.3.6";
int main()
{
int ival =246;
char szFormat[128]=".%d\n";
FORMAT_FUN(szPrex, szFormat);
//printf("%s\n", szFormat);
printf(szFormat, ival);// 1.3.6.246
return0;
}
1234567891011121314151617
举⼏个关于宏嵌套⽤法的例⼦:
Ex.1
#include<cstdio>
#define TO_STRING2(x) #x
#define TO_STRING(x)TO_STRING1(x)
#define TO_STRING1(x) #x
#define PARAM(x) #x
#define ADDPARAM(x) INT_##x
int main()
{
const char*str =TO_STRING(PARAM(ADDPARAM(1)));
printf("%s\n",str);
str =TO_STRING2(PARAM(ADDPARAM(1)));
printf("%s\n",str);
return0;
}
/*
output:
"ADDPARAM(1)"
PARAM(ADDPARAM(1))
*/
Ex.2
#include<stdio.h>
#define TO_STRING2(x) a_##x
#define TO_STRING(x)TO_STRING1(x)
#define TO_STRING1(x) #x
#define PARAM(x) #x
#define ADDPARAM(x) INT_##x
int main()
{
const char*str =TO_STRING(TO_STRING2(PARAM(ADDPARAM(1))));
printf("%s\n",str);
return0;
}
/*
VS2010 output:
a_PARAM(ADDPARAM(1))
GCC 4.3.2 output:
a_PARAM(INT_1)
*/ 1234567891011121314151617181920212223242526272829303132333435363738394041424344

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。