『 C 』 `##` 在 C 语言宏定义中的作用解析
文章目录
- `##` 运算符的基本概念
- 可变参数宏与 `##` 的应用
- 可变参数宏简介
- `##` 处理可变参数的两种情况
- 可变参数列表为空
- 可变参数列表不为空
- 示例代码验证
在 C 和 C++ 编程里,宏定义是个很有用的工具。今天咱们就来聊聊 ##
这个预处理器连接运算符在宏定义中的作用,特别是在可变参数宏里的应用。
##
运算符的基本概念
##
是预处理器的连接运算符,也叫“令牌粘贴”运算符。它能把两个预处理令牌连在一起,变成一个新的预处理令牌。在宏定义里,它主要用于处理可变参数。这部分内容在 C 语言标准文档里有明确说明,它是 C99 及以后标准支持的特性。
可变参数宏与 ##
的应用
可变参数宏简介
C99 引入了可变参数宏的概念。在宏定义里,...
表示可变参数部分,__VA_ARGS__
会被替换成实际传递的可变参数列表。比如下面这个 LOG
宏:
#define LOG(level, format, ...) { \
if (level >= LDEFAULT) { \
time_t t = time(NULL);\
struct tm *lt = localtime(&t);\
char time_tmp[32] = {0}; \
strftime(time_tmp, 31, "%m-%d %T", lt);\
fprintf(stdout, "[%s][%s:%d] " format "\n", time_tmp, __FILE__, __LINE__, ##__VA_ARGS__); \
} \
}
##
处理可变参数的两种情况
可变参数列表为空
当调用 LOG
宏时没传递可变参数,像 LOG(LINF, "No variable arguments");
,##
能消除 __VA_ARGS__
前面的逗号。要是没有 ##
,宏展开后会有多余逗号,导致编译出错。有了 ##
,可变参数为空时逗号会被移除,保证代码正确。
可变参数列表不为空
如果传递了可变参数,比如 LOG(LINF, "The sum is %d", a + b);
,##__VA_ARGS__
会被替换成实际的可变参数 a + b
,宏展开后就能正确把参数传给 fprintf
函数。
示例代码验证
下面是个简单示例,展示 LOG
宏的使用和 ##
的作用:
#include <stdio.h>
#include <time.h>
#define LDBG 0
#define LINF 1
#define LERR 2
#define LDEFAULT LINF
#define LOG(level, format, ...) { \
if (level >= LDEFAULT) { \
time_t t = time(NULL);\
struct tm *lt = localtime(&t); \
char time_tmp[32] = {0}; \
strftime(time_tmp, 31, "%m-%d %T", lt);\
fprintf(stdout, "[%s][%s:%d] " format "\n", time_tmp, __FILE__, __LINE__, ##__VA_ARGS__); \
} \
}
int main() {
int a = 10, b = 20;
LOG(LINF, "Starting the program");
LOG(LINF, "The sum of %d and %d is %d", a, b, a + b);
return 0;
}
在这个示例中,第一个 LOG
调用没传可变参数,第二个传了。因为用了 ##
,两种情况都能正确编译运行。
通过以上分析,我们能清楚看到 ##
运算符在处理可变参数宏时的重要性,它保证了代码的灵活性和正确性。希望大家在编程中能灵活运用这个特性。