抑制C宏变量替换

fer*_*lin 7 c substitution c-preprocessor

我有这段代码(实际上是垃圾收集的Forth系统的解释器的一部分):

#define PRIMITIVE(name) \
    do \
    { \
        VocabEntry* entry = (VocabEntry*)gc_alloc(sizeof(VocabEntry)); \
        entry->code = name; \
        entry->name = cstr_to_pstr(#name); \
        entry->prev = latest_vocab_entry; \
        latest_vocab_entry = entry; \
    } \ 
    while (false)

PRIMITIVE(dup);
PRIMITIVE(drop);
PRIMITIVE(swap);
// and a lot more
Run Code Online (Sandbox Code Playgroud)

但是有一个问题:在线

entry->name = cstr_to_pstr(#name);
Run Code Online (Sandbox Code Playgroud)

name字段被取代dup,drop,swap,和其余部分.我希望字段名称不被替换.

那么,有没有办法解决这个问题,除了简单地重命名宏参数?

作为答案,请解释一般是否有一种方法来抑制宏体中宏参数名称的替换.不要回答"只是这样做"(请).

Eri*_*hil 16

您可以定义一个不同的宏来扩展name,如下所示:

#define Name name
Run Code Online (Sandbox Code Playgroud)

并更改宏中的name字段PRIMITIVE以使用新宏,如下所示:

#define PRIMITIVE(name) \
    do \
    { \
        VocabEntry* entry = (VocabEntry*)gc_alloc(sizeof(VocabEntry)); \
        entry->code = name; \
        entry->Name = cstr_to_pstr(#name); \
        entry->prev = latest_vocab_entry; \
        latest_vocab_entry = entry; \
    } \ 
    while (false)
Run Code Online (Sandbox Code Playgroud)

除了使用与宏体中的参数名称不同的内容或更改参数名称之外,在C语言中没有其他方法可以执行此操作.根据C 2011(N1570)6.10.3.1 1,当识别出类似函数的宏时,除非存在###存在时立即替换参数名称,并且没有其他例外:

在确定了调用类函数宏的参数之后,发生了参数替换.替换列表中的参数除非前面带有#或##预处理标记或后跟##预处理标记(见下文),否则在扩展其中包含的所有宏之后,相应的参数将替换该参数.

#令牌改变参数名称为一个字符串,这是在这种情况下没有用.该##令牌扩展参数名和与相邻的道理,这也是在这种情况下没有使用起来要粘贴它.


Leu*_*nko 5

不,那里没有.

要了解原因,您需要考虑宏扩展实际发生的方式.扩展类似函数的宏需要三个主要步骤:

  1. 宏的参数是完全展开的,除非宏在它们上使用###运算符(在示例中不相关,因为它们是单个标记)
  2. 整个替换列表进行扫描,参数名称的任何发生由相应的参数替换
  3. 在步骤2完成之后,扩展的替换列表本身被重新扫描,并且此时出现的任何宏都被扩展

标准6.10.3节(C11和C99)对此进行了概述.

这样做的结果是,不可能编写某种可以采取name和滥用'##'或类似内容的抑制规则的宏,因为正文中的替换步骤PRIMITIVE 必须在任何宏之前完全运行在体内允许他们轮到被识别.您无法在替换列表中标记令牌以进行抑制,因为只有在替换步骤已经运行后才能检查您可以放置​​的标记.由于订单是在标准中指定的,因此您发现的任何可以让您以这种方式标记令牌的漏洞都是编译器错误.

最好我可以建议,如果你真的没有重命名宏参数是为了传递name作为连接宏的单独参数; name只有在替换完成后才会形成令牌,并且不再检查列表中的参数名称.

编辑希望我输入更快.

  • 为什么你的回答一开始就断言没有办法,然后又给出了办法? (2认同)