来自公众号:裸机思维C语言中一个重要的内容,就是 ## 的用法,可能绝大部分 C 程序员都不知道"##"隐藏用法,下面就来给大家讲讲。
一、##的“表”用法
想必很多人都知道"##"的用法——它本质上是一个“胶水运算”(连接字符串的作用),用于把参数宏中的“形参”与其它没有天然分割的内容粘连在一起,例如:
#define def_u32_array(__name, __size) uint32_t array_##__name[__size];
实际中,我们可以这样使用:
def_u32_array(sample_buffer, 64)
宏展开的效果是:
uint32_t array_sample_buffer[64];
可以看到,"array__"与形参“__name”是没有天然分割的,因此要想将"array_"与"__name"所代表的内容(而不是__name本身)粘连在一起,就需要“##”运算的帮助。
另一方面,"__name"与"["是具有天然分隔的——编译器不会认为"__name"与"["是连接在一起的,因此这里并不需要画蛇添足的使用"##"运算——如果你这么做了,预编译器会毫不犹豫的告诉你语法错误。——这是"##"运算的普通用法,在过去转载的文章《C语言#和##连接符在项目中的应用(漂亮)》中也有详细介绍,这里就不再赘述。
二、## 的官方“里”用法
“##”还有一个很少为人所知的“里”用法,在介绍它之前,不得不首先说说由ANSI-C99标准引入的另外一个参数宏扩展——可变参数宏。举个例子:
#define safe_atom_code(...) \ { \ uint32_t int_flag = __disable_irq(); \ __VA_ARGS__ \ __set_PRIMASK(int_flag); \ }
这里定义了一个宏"safe_atom_code()",在括号内,无论你填写任何内容,都会被无条件的放置到“__VA_ARGS__”所在的位置,你可以认为括号里的“...”实际上就是对应"__VA_ARGS__"。比如,我们可以写下这样的