【C语言编程】宏用法

正文

宏用法

在一个宏中的参数前面使用一个#,预处理器会把这个参数转换为一个字符数组,简化理解:#是“字符串化”的意思,出现在宏定义中的#是把跟在后面的参数转换成一个字符串

#define ERROR_LOG(module)   fprintf(stderr,"error: "#module"\n")

即:

ERROR_LOG("add"); 转换为 fprintf(stderr,"error: "add"\n");
ERROR_LOG(devied=0); 转换为 fprintf(stderr,"error: devied=0\n");

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

#define TYPE1(type,name)   type name_##type##_type
#define TYPE2(type,name)   type name##_##type##_type

即:

TYPE1(int, c); 转换为:int  name_int_type ; (因为##号将后面分为 name_ 、type 、 _type三组,替换后强制连接)
TYPE2(int, d);转换为: int  d_int_type ; (因为##号将后面分为 name、_、type 、_type四组,替换后强制连接)

 

__VA_ARGS__ 是 C 预处理器的一个特性,用于处理可变参数宏。它允许你在宏定义中传递不定数量的参数。这里“…”指可变参数。这类宏在被调用时,它(这里指“…”)被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。当被调用时,在宏体中,那些符号序列集合将代替里面的__VA_ARGS__标识符,用法示例如下:

#include <stdio.h>

#define PRINTF(format, ...) printf(format, __VA_ARGS__)

int main() {
    PRINTF("Hello, %s! You have %d new messages.\n", "Alice", 5);
    return 0;
}

如果没有提供可变参数,使用 __VA_ARGS__ 时可能会导致编译错误。可以使用 GNU C 扩展来避免这种情况。例如:

#define LOG(level, ...) \
    do { \
        printf("[%s] ", level); \
        printf(__VA_ARGS__); \
    } while (0)

#define LOG_INFO(msg) LOG("INFO", msg)

int main() {
    LOG_INFO("This is an info message\n");
    LOG("ERROR", "An error occurred: %s\n", "File not found");
    return 0;
}

注意事项

  1. 参数分隔符:如果可变参数为空,__VA_ARGS__ 在某些情况下可能会导致编译错误,尤其是在没有传递任何参数时。确保在使用之前进行适当的检查。

  2. 格式化字符串:确保格式化字符串和后续参数数量匹配,以避免未定义的行为。

  3. 标准兼容性:__VA_ARGS__ 是 C99 及更高版本的特性,确保你的编译器支持。

 

可以结合其他宏来实现更复杂的功能,例如动态生成多个日志记录:

#define LOG(level, count, ...) \
    do { \
        printf("[%s] ", level); \
        for (int i = 0; i < count; i++) { \
            printf(__VA_ARGS__); \
        } \
    } while (0)

int main() {
    LOG("DEBUG", 3, "This is a debug message\n");
    return 0;
}

 

对于可变参数为空的情况,可以使用 ##__VA_ARGS_ : 宏前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的","去掉的作用,否则会编译出错。

#include <stdio.h>

#define DEBUG2(format, ...) do { \
    printf(format, ##__VA_ARGS__); \
} while (0)

int main() {
    int value = 42;

    DEBUG2("Debug: The value is %d\n", value);  // 输出: Debug: The value is 42
    DEBUG2("Debug: No additional info.\n");      // 输出: Debug: No additional info.

    return 0;
}

1. #用来把参数转换成字符.

2. ##这个运算符把两个语言符号组合成单个语言符号

3.  __VA_ARGS__ 是一个可变参数的宏,实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点)。

 

 

参考资料

1. C语言 ## __VA_ARGS__ 宏

2. 整理:C/C++可变参数,“## __VA_ARGS__”宏的介绍和使用

posted @   苏格拉底的落泪  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2018-05-21 【C++编程】移动构造函数
2018-05-21 【Python】json编码和解码器
点击右上角即可分享
微信分享提示