宏扩展:与逗号的争论 [英] Macro Expansion: Argument with Commas

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

问题描述

我正在处理的代码使用一些非常复杂的宏伏都教(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警告not enough actual parameters for macro 'MACROFUNC_INNER'.

  • 是否有可能使MSVC通过一些技巧进行扩展(另一层宏强制进行第二次扩展,某些位置适当的##或#,...).承认不能改变构造的工作方式. (即:我可以自己解决问题吗?)
  • 关于这种极端情况,C标准怎么说?我在C11规范中找不到任何明确告诉您如何处理包含参数列表的参数的内容. (即,我可以与代码作者争辩说他必须再次编写它,或者只是MVSC不符合要求?)
  • Is it possible to get MSVC do the expansion with some tricks (another layer of macro to force a second expansion, some well placed ## or #, ...). Admitting that changing the way the construct work is not an option. (i.e.: can I solve the problem myself?)
  • What does the C standard say about such corner case? I couldn't find in the C11 norm anything that explicitly tells how to handle arguments that contains a list of arguments. (i.e.: can I argue with the author of the code that he has to write it again, or is just MVSC non-conform?)

推荐答案

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.

(上面的内容大多忽略了与该问题无关的字符串化(#)和令牌串联(##).)

(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,并已在此处验证),以下符合标准的解决方法适用于某些版本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替换替换列表中的所有参数之后,然后重新扫描生成的预处理令牌序列以及源文件的所有后续预处理令牌,以替换更多的宏名称.

§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天全站免登陆