[c语言]宏中##的用法(续)

如下代码,不明觉厉。
#   define ext2_debug(f, a...)  { \
                     printk ("EXT2-fs DEBUG (%s, %d): %s:", \
                         __FILE__, __LINE__, __func__); \
                     printk (f, ## a); \
                     }
特别是其中printf(f, ## a);这样的用法。
Google之后在stackoverflow找到了这个问题以及解答。
链接:http://stackoverflow.com/questions/13225921/in-printk-what-does-mean
详细的解答跳转到了GNU的gcc文档:
原文链接:https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
译文如下:
3.6 Variadic Macros (可变参数的宏)
一个宏可以像一个函数一样,接收数量可变的参数。这样的语法在宏中的定义与在函数中的定义是类似的。
这里是一个例子。
         #define eprintf(...) fprintf (stderr, __VA_ARGS__)
这种宏被称为 variadic.。当这种宏被调用时,参数列表中在最后一个被命名参数之后的所有字段,包括所有逗号,都变为可变的参数( variable argument )。标识符 __VA_ARGS__ 无论出现在宏的什么位置,都将被这一系列的字段替换掉。
因此,我们可以得到这样的表达式。
         eprintf ("%s:%d: ", input_file, lineno)
          ==>  fprintf (stderr, "%s:%d: ", input_file, lineno)
可变参数在插入到宏的表达式之前,是一个完整的宏的扩展,就像普通的参数一样。你可以使用#将操作符转化为字符串,也可以使用##将多个字段连接为一个字段。(但是,如下将展示##的一个重要的特别用法。)
 如果你的宏是复杂的,对于可变的参数,你应该想要一个比 __VA_ARGS__ 更具有表达性的名字。作为一个表达方式,CPP允许这一点。你可以在“...”之前写一个参数的名字,用于表达这个参数是可变参数。
之前的eprintf宏可以使用这样的表达方式被写为:
            #define   eprintf (args...) fprintf (stderr, args)
注意,不可以在同一个宏中同时使用这种表达方式和 __VA_ARGS__。
你也可以使用 __VA_ARGS__ 在一个可变参数的宏中 来表达可变的参数。
我们将像这样来重新定义eprintf。
         #define eprintf(format, ...) fprintf (stderr, format, __VA_ARGS__)
这样的方式看起来更加具有可读性,但是这样的方式缺乏适应性:在格式化的参数之后,我们必须提供至少一个参数。在标准C中,你不能在命名参数和可变参数之间省略逗号。而且,如果你保留可变参数为空,你将得到一个编译错误,因为在格式化参数的后面将多出一个逗号。
         eprintf("success!\n", );
          ==> fprintf(stderr, "success!\n", );
GNU CPP提供两种表达式,可以处理这个问题。
第一种,你将被允许不添加整个可变的参数
          eprintf("success!\n" );
          ==> fprintf(stderr, "success!\n", );
第二种,字段连接操作符##被放在一个逗号和一个可变的参数之间时,具有一种特殊的意义。
如果你写了如下表达式:
         #define eprintf(format, ...) fprintf (stderr, format, ##__VA_ARGS__)
当eprintf这个宏被调用时,可变的参数被省略,然后##之前的逗号被删除。如果输入一个空的参数,这个过程将不会发生;如果##之前的字段不是逗号,这个过程也不会发生。
         eprintf("success!\n");
          ==> fprintf(stderr, "success!\n");

====(未完待续,睡觉先)====
========接上回分解=======
以上的解释是针对一种情况,唯一的宏参数为一个可变变量的参数。这样的解释是含糊不清的。而尝试区分没有参数的情况是否是一个空参数或者一个错误参数是没有意义的。在这种情况下,C99标准清楚的表明逗号必须保留,然而现存GCC扩展版习惯于吞掉逗号。所以当CPP依照C99标准时,CPP保留逗号 ,而其他的则删除逗号。

C99提出来唯一的一处要求:标识符__VA_ARGS__能够出现在一个可变变量宏的替换列表里。但是这个标识符不可以作为一个宏的名字,宏的参数名,或者在一个不同类型的宏中。这个表示也禁止在open text中使用;标准是不明确的。我们推荐避免它的其他用法,除了它被定义用法。(open text是什么,我也没明白,Google也没找到合理解释。)

可变变量的宏是一个C99中的新功能。GNU CPP 已经支持这个功能很长时间,但是只支持一钟可变参数的命名(支持‘args...’;不支持'...' 和 __VA_ARGS__)。如果你考虑对GCC之前版本的兼容性,那么你应当只使用被命名的可变变量'args...'。另一方面,如果你考虑依照C99的实现,你应当只使用__VA_ARGS__。

之前版本的CPP实现了更加通用的针对逗号删除的扩展。在此份文档中,我们限制了这一点,为了使得与C99的差异最小。为了在此版GCC和之前的GCC版本中获得同样的作用,‘##’之前的字段必须是一个逗号,并且在逗号和逗号之前的任何字段之间必须有一个空格:
          #define eprintf(format, args...) fprintf (stderr, format , ##args)

======翻译部分完结======
C的标准之间,也是略有差异的。有一些特别的写法,可能是某个标准的特殊用法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
04-26
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值