c语言里的可变参数宏及##

有时我们写程序可能会定义许多DEBUG模式下的调试打印信息宏来替代原有的打印函数,这时就会出现编写可变量参数宏的写法问题,下面就摘要性的写一下,运行及调试环境为rh linux 9.0+gcc 3.2.2
首先在gcc中,对可变量参数宏的支持要强的多,一般我们可以这么写:
#define MACRO_1(fmt, args...) printf(fmt, args)
#define MACRO_2(fmt, ...) printf(fmt, __VA_ARGS__)
这两种写法都可以,后面一种是使用了关键字__VA_ARGS__,它代表宏中出现的...,而前面的写法就是给可变量的参数定义了一个名字,就是说在第一种写法中,args就是代表可变量参数,给出例子:
#include <stdio.h>
#define MACRO_1(fmt, args...) printf(fmt, args)
#define MACRO_2(fmt, ...)     printf(fmt, __VA_ARGS__)
int main()
{
        MACRO_1("MACRO_1:%s\n", "Hello");
        MACRO_2("MACRO_2:%s\n", "Hello");
        return 0;
}
我们可以用gcc -E的参数来得到程序的宏展开源代码,主要部分如下:

int main()
{
        printf("MACRO_1:%s\n", "Hello");
        printf("MACRO_2:%s\n", "Hello");
        return 0;
}
大家可以看到这里的对比.但有一个问题就是,如果我们只传递一个参数会怎么呢?也就是把源代码改写如下:
#include <stdio.h>
#define MACRO_1(fmt, args...) printf(fmt, args)
#define MACRO_2(fmt, ...)     printf(fmt, __VA_ARGS__)
int main()
{
        MACRO_1("MACRO_1\n");
        MACRO_2("MACRO_2\n");
        return 0;
}
这样会不会有问题呢,我们看一下宏展开后的代码:
int main()
{
        printf("MACRO_1\n" , );
        printf("MACRO_2\n" , );
        return 0;
}
这里多出现了一个",",问题的解决方法是在args和__VA_ARGS__前面加一个##,##表示去除它前面的",",但当我们传递多于一个参数的时候这也能工作,就像第一段代码一样,现在看一下加了##之后的代码及相应宏展开后的代码:
#include <stdio.h>
#define MACRO_1(fmt, args...) printf(fmt, ##args)
#define MACRO_2(fmt, ...)     printf(fmt, ##__VA_ARGS__)
int main()
{
        MACRO_1("MACRO_1\n");
        MACRO_2("MACRO_2\n");
        return 0;
}
展开宏之后:
int main()
{
        printf("MACRO_1\n");
        printf("MACRO_2\n");
        return 0;
}
问题解决了~_~。
其实,##在c语言里功能不只是这个,它还可以起到连接两个变量的作用,看下面的代码:
#include <stdio.h>
#define UNION(a,b) (a##b)
int main()
{
        char* long_long_var_prt = "Hello,world!";
        printf("Test:\nSTR:%s\tNUM:%d\n",  UNION(long_, long_var_prt), UNION(10,8));
        return 0;
}
这里开了一个小玩笑,就是把一个字符串的名字起得很长,然后再通过##把它们粘起来并输入,后面是把两个整数合并到一起,组成一个大的整数,展开宏之后的代码如下:
int main()
{
        char* long_long_var_prt = "Hello,world!";
        printf("Test:\nSTR:%s\tNUM:%d\n", ( long_long_var_prt), ( 108));
        return 0;
}
输出如下:
Test:
STR:Hello,world!        NUM:108
OVER,快乐编程。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
c语言中的函数是一种定义的形式,可以在编译预处理阶段通过替换来实现类似函数调用的功能。它不同于普通的函数调用,其主要特点是在定义时使用一些特殊的形参,这些形参可以包含可变参数可变参数是指函数在调用时可以传入不定数量的参数。在定义中,我们可以使用"..."来表示可变参数,且该参数必须放置在参数列表的最后。 通过定义中的可变参数,我们可以通过函数实现一些功能较为复杂的操作。比如,我们可以编写一个求和的函数,可以传入任意数量的参数,并对它们进行求和计算。例如: ``` #define SUM(...) sum(__VA_ARGS__) int sum(int count, ...) { int result = 0; va_list arg; va_start(arg, count); for(int i = 0; i < count; i++) { result += va_arg(arg, int); } va_end(arg); return result; } ``` 在使用可变参数函数时,我们需要使用定义中的特殊形参,包括`va_list`、`va_start`、`va_arg`和`va_end`。`va_list`是一个用于存储可变参数的类型,`va_start`用于初始化可变参数的访问,`va_arg`用于按顺序获取可变参数的值,`va_end`用于结束对可变参数的访问。 总之,函数和可变参数C语言中非常有用的功能,可以通过它们来实现一些复杂的操作和功能。但需要注意的是,在使用可变参数时要小心,保证参数的正确性和合法性,以免出现错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值