宏扩展:带逗号的参数 [英] Macro Expansion: Argument with Commas

查看:18
本文介绍了宏扩展:带逗号的参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理的代码使用了一些非常复杂的宏 voodoo 来生成代码,但最终有一个看起来像这样的构造

The code I'm working on uses some very convoluted macro voodoo in order to generate code, but in the end there is a construct that looks like this

#define ARGS 1,2,3

#define MACROFUNC_OUTER(PARAMS) MACROFUNC_INNER(PARAMS)
#define MACROFUNC_INNER(A,B,C) A + B + C

int a = MACROFUNC_OUTER(ARGS);

期望得到的是什么

int a = 1 + 2 + 3;

这适用于最初为 (GHS) 和 GCC 编写的编译器,但 MSVC (2008) 将 PARAMS 视为单个预处理标记,它不会扩展,设置然后 A 到整个 PARAMBC 到什么都没有.结果是这样的

This works well for the compiler it has originally been written for (GHS) and also for GCC, but MSVC (2008) considers PARAMS as a single preprocessing token that it won't expand, setting then A to the whole PARAM and B and C to nothing. The result is this

int a = 1,2,3 +  + ;

而 MSVC 警告 没有足够的实际参数用于宏 'MACROFUNC_INNER'.

while MSVC warns that not enough actual parameters for macro 'MACROFUNC_INNER'.

  • 是否可以通过一些技巧让 MSVC 进行扩展(另一层宏强制进行第二次扩展,一些放置得当的 ## 或 #,...).承认改变构造的工作方式不是一种选择.(即:我可以自己解决问题吗?)
  • C 标准对这种极端情况有什么看法?我在 C11 规范中找不到任何明确说明如何处理包含参数列表的参数的内容.(即:我可以与代码的作者争论他必须重新编写它,还是只是 MVSC 不符合?)

推荐答案

MSVC 不符合要求.该标准实际上在这一点上很明确,尽管它认为没有必要提及这种特殊情况,这并不例外.

MSVC is non-conformant. The standard is actually clear on the point, although it does not feel the need to mention this particular case, which is not exceptional.

当遇到类似函数的宏调用时,预处理器:

When a function-like macro invocation is encountered, the preprocessor:

  1. §6.10.3/11 标识参数,这些参数可能是由非受保护逗号分隔的标记的空序列 ,(如果逗号在括号 内,则逗号受到保护()).

  1. §6.10.3/11 identifies the arguments, which are possibly empty sequences of tokens separated by non-protected commas , (a comma is protected if it is inside parentheses ()).

§6.10.3.1/1 对宏主体进行第一次遍历,将 ### 操作中未使用的每个参数替换为相应的完全宏扩展的参数.(在此步骤中,它不会在宏体中进行其他替换.)

§6.10.3.1/1 does a first pass over the macro body, substituting each parameter which is not used in a # or ## operation with the corresponding fully macro-expanded argument. (It does no other substitutions in the macro body in this step.)

§6.10.3.4/1 重新扫描替换的替换标记序列,并根据需要执行更多宏替换.

§6.10.3.4/1 rescans the substituted replacement token sequence, performing more macro replacements as necessary.

(以上大多忽略了与本题无关的字符串化(#)和token串联(##).)

(The above mostly ignores stringification (#) and token concatenation (##), which are not relevant to this question.)

这种操作顺序明确地导致了编写软件的人所期望的行为.

This order of operations unambiguously leads to the behaviour expected by whoever wrote the software.

显然(根据@dxiv,并在here 验证)以下符合标准的解决方法适用于某些版本MS Visual Studio:

Apparently (according to @dxiv, and verified here) the following standards-compliant workaround works on some versions of MS Visual Studio:

#define CALL(A,B) A B
#define OUTER(PARAM) CALL(INNER,(PARAM))
#define INNER(A,B,C) whatever

作为参考,来自 C11 标准的实际语言,跳过对 ### 处理的引用:

For reference, the actual language from the C11 standard, skipping over the references to # and ## handling:

§6.10.3 11 由最外面的匹配括号界定的预处理标记序列形成了类函数宏的参数列表.列表中的各个参数由逗号预处理标记分​​隔,但匹配内括号之间的逗号预处理标记不分隔参数....

§6.10.3 11 The sequence of preprocessing tokens bounded by the outside-most matching parentheses forms the list of arguments for the function-like macro. The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate arguments.…

§6.10.3.1 1 在确定了调用类函数宏的参数后,将进行参数替换.替换列表中的参数…在其中包含的所有宏都被展开后被相应的参数替换.在被替换之前,每个参数的预处理标记都被完全宏替换,就好像它们形成了预处理文件的其余部分......

§6.10.3.1 1 After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list… is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file…

§6.10.3.4 1 在替换列表中的所有参数都被替换后……[t]然后重新扫描生成的预处理标记序列以及源文件的所有后续预处理标记,以替换更多宏名称.

§6.10.3.4 1 After all parameters in the replacement list have been substituted… [t]he resulting preprocessing token sequence is then rescanned, along with all subsequent preprocessing tokens of the source file, for more macro names to replace.

这篇关于宏扩展:带逗号的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆