【C语言】宏定义知识点小记

一、一处修改,全局生效

#define PI ((double)3.1415926)

对于圆周率这种特殊的值,可以使用宏值替换,方便以后对于精度的修改等。

二、简化代码

#define MAX_VAL(v1, v2) ((v1) > (v2) ? (v1) : (v2))

上面的宏用于获取两个值里面的较大值,在定义的宏里面,必要的括号是不可少的;虽然上面的宏加上了很多括号,但是在下面的语句中仍然会存在问题,虽然也有其他方式可以解决这样子的问题,但是在编码过程中还是不建议在宏里面出现这样子的操作,包括一些函数调用。

MAX_VAL(a++, b++)

三、宏中使”{}”

#define SWAP_INT(v1, v2)\
    {\
        int tmp = 0;\
        tmp = v1;\
        v1  = v2;\
        v2  = tmp;\
    }

上面的宏的作用是交换两个int的值,在定义的宏中涉及多条语句时,需要使用”{}”,这样子可以将多条语句作为一个代码块实现。

四、宏定义用”do{ }while(0)”

if (v1 < v2)
    SWAP_INT(v1, v2);
else
printf("swap_int : v1 = %d, v2 = %d.\n", v1, v2);

上面的语句使用SWAP_INT宏,编译时报错,因为else没有对应的if。可以修改成下面的形式,编译时就不会发生错误了。

#define SWAP_INT(v1, v2)\
    do{\
        int tmp = 0;\
        tmp = v1;\
        v1  = v2;\
        v2  = tmp;\
    }while(0)

采用这样子好处是可以避免分号带来的麻烦,类似定义了一个代码块,可以实现一个较复杂的功能,并且不会与上下文混淆。类似的宏经常在代码中出现来提升代码的健壮性。

五、宏定义用”#”

在一个宏中的参数前面使用一个#,预处理器会把这个参数转换为一个字符数组。

#define ERROR_LOG(module)   fprintf(stderr, "error: "#module"\n")
#define PRINT_PARAM(param)  printf("%s=%d\n",#param, param)

下面的语句执行的效果如下:

ERROR_LOG(max_val);	->	error: max_val
ERROR_LOG("v1 = 0, v2 = 10");	->	error: "v1 = 0, v2 = 10"
PRINT_PARAM(v1);	->	v1=10
PRINT_PARAM(v1 + v2);	->	v1 + v2=10

六、宏定义用”##”

“##”是一种分隔连接方式,它的作用是先分隔,然后进行强制连接。
在普通的宏定义中,预处理器一般把空格解释成分段标志,对于每一段和前面比较,相同的就被替换。但是这样做的结果是,被替换段之间存在一些空格。如果我们不希望出现这些空格,就可以通过添加一些##来替代空格。

#define STR_CAT(src1, src2) 	(src1 src2)	//GCC使用##连接字符串编译报错替换成空格即可
#define CAT_PARAM(p1, p2)   (p1##p2)
#define TYPE1(type,name)   type name_##type##_type 
#define TYPE2(type,name)   type name##_##type##_type

下面的语句执行的效果如下:

 int num = CAT_PARAM(12, 32);		 ->	num = 1232
 char *pDst = STR_CAT("acb", "def"); ->	pDst = acbdef
 TYPE1(int, c);  -> int  name_int_type ; (因为##号将后面分为 name_ 、type 、 _type三组,替换后强制连接)
 TYPE2(int, d);	 -> int  d_int_type ;    (因为##号将后面分为 name、_、type 、_type四组,替换后强制连接)

七、宏定义用typeof

typeof 需要头文件<stddef.h>,它经常出现在宏定义中用来获得变量的类型,如下:

#define min(x, y) ({                    \
	    typeof(x) _min1 = (x);          \
	    typeof(y) _min2 = (y);          \    
	    (void) (&_min1 == &_min2);      \    
        _min1 < _min2 ? _min1 : _min2; })

这里主要说明一下:

(void) (&_max1 == &_max2);

这一句很有意思:看起来是一句废话,其实用得很巧妙!它主要是用来检测宏的两个参数 x 和 y 的数据类型是否相同。如果不相同,编译器会给一个警告信息,提醒程序开发人员。

warning:comparison of distinct pointer types lacks a cast

八、可变参数宏 … 和 _ VA_ARGS _

#define PRINT(...) printf(__VA_ARGS__)
#define LOG(format, args...) fprintf(stdout, format, args)  // args...可以理解为给可变参数...起别名,否则使用__VAR_ARGS__
LOG("%s","123"); //正确 
LOG("123"); //错误 展开后,相当与LOG(,"123") 
#define LOG(format, args...) fprintf(stdout, format, ##args)
LOG("%s","123"); //正确 
LOG("123"); //正确 ##加上后不会进行连接。

##”连接符号的用法,“##”的作用是对token进行连接,上例中format,args都可以看作是token,如果token为空,“##”则不进行连接,所以允许省略可变参数 因为format这个token为空,又因为有##的加持,所以不连接。
##这个连接符号充当的作用就是当__VAR_ARGS__或者args为空的时候,消除前面的那个逗号

九、当宏参数是另一个宏的时候

需要注意的是凡宏定义里有用’#‘或’##'的地方宏参数是不会再展开,例如:

#define STR(s)     #s 
printf("int max: %s\n",  STR(INT_MAX));    // INT_MAX #include<climits> 
这行会被展开为: 
printf("int max: %s\n", "INT_MAX"); 

参考网址

https://www.cnblogs.com/alantu2018/p/8465911.html
https://zhuanlan.zhihu.com/p/55771861
https://www.cnblogs.com/hnrainll/archive/2012/08/15/2640558.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值