今天遇到一个关于可变参数的问题,下面先给出一个示例程序说明我遇到的问题。
0 #include <stdio.h>
1
2 #define print(fmt, ...) out(fmt, __VA_ARGS__)
3 #define out(fmt, ...) printf(fmt, __VA_ARGS__)
4
5 int main(int argc, char** argv)
6 {
7 print("hello %d\n", 0);
8 print("hello\n");
9 return 0;
10 }
  为了说明问题,上面有两个print宏调用,出问题的是第二个。 用gcc编译的时候给出错误提示:"7:2: error: expected expression before ')' token"。

  gcc的错误提示说明第8行的无参数的宏print调用是错误的。原因清晰,第八行的"hello\n"后面没有给出参数,导致"printf(fmt, __VA_ARGS__)"编译后成了"printf("hello\n", )",原因很清楚了。

  那么,为了去掉gcc 编译错误,我是不是得把第8行代码改成第7行的样式凑合着用?
  经过半天google,在 http://hi.baidu.com/pragmatist/item/591a8a4ccbd643086dc2f035 得到了答案(补充一下,百度真垃圾,自己搜自己的网页,还是没有给出我想要的答案)。文中有提示"##符号在 逗号 和 参数名 之间时不做连字符作用,而作为变参宏的特别用处",我急忙把程序修改成如下代码:
1 #include <stdio.h>
2
3 #define print(fmt, ...) out(fmt, __VA_ARGS__)
4 #define out(fmt, ...) printf(fmt, ##__VA_ARGS__)
5
6 int main(int argc, char** argv)
7 {
8 print("hello %d\n", 0);
9 print("hello\n");
10 return 0;
11 }
  我只修改了第4行的代码,此时gcc仍然给我相同的提示,难道我用错了?没办法了,只好找来同事帮忙。同事很给力了,一见代码,就见了亲人,说,再把第三行修改一下。最终代码如下:
1 #include <stdio.h>
2
3 #define print(fmt, ...) out(fmt, ##__VA_ARGS__)
4 #define out(fmt, ...) printf(fmt, ##__VA_ARGS__)
5
6 int main(int argc, char** argv)
7 {
8 print("hello %d\n", 0);
9 print("hello\n");
10 return 0;
11 }

  通过gcc -E test.c,得到如下代码:

int main(int argc, char** argv)
{
 printf("hello %d\n", 0);
 printf("hello\n");
 return 0;
}
  此时,预编译后的代码中第8行的结果中没有烦人的逗号,一切都很美好,gcc的错误提示没有了。再次领略静心细心的重要性。

  建议以后使用变参__VA_ARGS__都以##__VA_ARGS__的形式使用。

转载于:https://www.cnblogs.com/menggucaoyuan/archive/2012/10/11/2720466.html

怎样安全的使用可变参数宏__VA_ARGS__相关推荐

  1. #{}不自动改参数类型_【Just For Fun】C - 可变参数函数、可变参数宏 __VA_ARGS__、额外的逗号

    [Just For Fun] 本系列纯粹娱乐.研究用.一些旁门左道的东西. 事实上可能完全没用. (๑•̀ω•́๑) 對於可变参数函数.可变参数宏 __VA_ARGS__ , 我曾經有在另一些地方寫過 ...

  2. linux c程序加args,C/C++可变参数,“## __VA_ARGS__”宏的介绍和使用

    在阅读代码的时候,在一个宏定义语句中,发现了个之前未曾见过的编译器预定义宏:"__VA_ARGS__".当时,从代码语句中推测它代表宏参数:"-"(本文称之为省 ...

  3. 【嵌入式】C语言高级编程-可变参数宏(12)

    00. 目录 文章目录 00. 目录 01. 可变参数宏概述 02. ##符号 03. 可变参宏另外一种写法 04. 内核中的可变参数宏 05. 附录 01. 可变参数宏概述 #include < ...

  4. c语言宏定义可变参数,C语言可变参数宏定义方法

    http://blog.csdn.net/skyflying2012/article/details/38436711 2014 在GNU C中,宏可以接受可变数目的参数,就象函数一样,例如: 1 2 ...

  5. c语言宏不能传递参数,关于c ++:可变参数宏:不能通过’…’传递非平凡复制类型的对象...

    我正在尝试为日志记录机制编写宏. 我编写了一个可变参数宏,但它不适用于std::string. 该代码如下所示: #include #include #define LOG_NOTE(m, ...) ...

  6. 巧用可变参数宏、编译器内置宏和printf输出调试信息

    前言: 我们在写程序的时候,总是或多或少会加入一些printf之类的语句用于输出调试信息,但是printf语句有个很不方便的地方就是当我们需要发布程序的时候要一条一条的把这些语句删除,而一旦需要再次调 ...

  7. 【valist】c语言可变参数宏

    va_list 是C语言中解决变参问题的一组宏. 1.API介绍: 头文件: [cpp]  view plain copy print ? #include <stdarg.h> 下面是实 ...

  8. ## __VA_ARGS__ ... 宏和可变参数

    在GNU C中,宏可以接受可变数目的参数,就象函数一样,例如: 1 2 #define pr_debug(fmt,arg...) \ printk(KERN_DEBUG fmt, ##arg) 用可变 ...

  9. c语言 可变参数的宏,可变参数的宏__ VA_ARGS__的用法

    回顾 在[ANSIC几种特殊的标准定义]中我们讲述了比较常用的几项: __FILE__:正在编译文件的路径及文件名 __LINE__:正在编译文件的行号 __DATE__:编译时刻的日期字符串 如&q ...

最新文章

  1. android在控制台签名apk
  2. 缓存一致性(MESI)
  3. css--css选择器,伪类
  4. python 多线程并发编程(生产者、消费者模式),边读图像,边处理图像,处理完后保存图像实现提高处理效率
  5. asp.net 下载文件
  6. 新手必看!单片机掉电检测与数据掉电保存方案
  7. java实体类 判断 字段_java8 根据实体类中的某个字段对实体类去重
  8. Centos、Ubuntu的区别
  9. oracle递归查询出现死循环,oracle 递归查询求出起点、终点问题的解决方法
  10. apache 访问控制
  11. Egert实现五点连线(创意参考:网易爱的不同定义)[附源码]
  12. 列举几个:MAC OS科研软件推荐
  13. 计算机速成课 第二集 电子计算机
  14. LeetCode-Python-274. H指数
  15. jqwidgets技术分享
  16. 学生请假管理系统(需求说明+项目(部分代码))
  17. U盘启动模式USB-HDD/HDD+/ZIP/ZIP+/CDROM/FDD的区别
  18. A Complete ActiveX Web Control Tutorial
  19. 苹果手机(iPhone)系统升级到IOS16.1后,发现连接WiFi、热点总是经常自动(随机)断开
  20. Lync 2010升级到2013之部署企业语音!

热门文章

  1. Win7 配置Android开发环境
  2. oracle入门学习(3) 所用的学习环境介绍与设置
  3. 使用ASP.Net 3.5 的Ajax与Web服务开发实例
  4. 使用Excel 通过 ODBC 连接到 MySQL 数据库
  5. lvs十种调度策略+三种模式
  6. RMAN backup validate database on databases in noarchivelog mode
  7. 最近在学OpenGL和英语
  8. Linux下不同服务器间数据传输
  9. windows根据端口号找进程
  10. 团队项目的分工及绩效评估方法