python展开 c函数中的宏预处理_如何与C预处理器连接两次并展开宏(如“arg#宏”中的宏)?...

标准C预处理器$ cat xx.c#define VARIABLE 3#define PASTER(x,y) x ## _ ## y#define EVALUATOR(x,y)  PASTER(x,y)#define NAME(fun) EVALUATOR(fun, VARIABLE)

extern void NAME(mine)(char *x);$ gcc -E xx.c# 1 "xx.c"# 1 ""# 1 ""# 1 "xx.c"extern void mine_3(char *x);$

两级间接

在对另一个答案的评论中,卡德鲁 问为什么这需要两个层次的间接。轻率的答案是,因为这是标准要求它工作的方式;你往往会发现,你也需要与字符串操作符一样的技巧。

C99标准第6.10.3节涵盖“宏替换”,6.10.3.1涵盖“参数替换”。在确定了调用类似于函数的宏的参数之后,就会发生参数替换。替换列表中的参数,除非前面有#或##预处理令牌或后面是##预处理令牌(见下文),在展开其中包含的所有宏后,将被相应的参数替换。在被替换之前,每个参数的预处理标记都会被宏完全替换,就好像它们构成了预处理文件的其余部分一样;没有其他的预处理标记可用。

在调用中NAME(mine),该参数为“my”;它被完全展开为“my”;然后将其替换为替换字符串:EVALUATOR(mine, VARIABLE)

现在,宏评估器被发现,参数被隔离为‘my’和‘Variable’;后者随后被完全展开为‘3’,并被替换成替换字符串:PASTER(mine, 3)

其他规则(6.10.3.3‘#操作符’)涵盖了这方面的操作:如果在类似函数的宏的替换列表中,参数紧跟在##预处理令牌,将参数替换为相应参数的预处理令牌序列;[.]

对于类似对象的宏调用和类似函数的宏调用,在重新检查替换列表以获得要替换的更多宏名称之前,##替换列表中的预处理令牌(不是从参数中删除)被删除,并将前面的预处理令牌与以下预处理令牌连接起来。

因此,替换列表包含x紧随其后##还有##紧随其后y因此,我们有:mine ## _ ## 3

和消除##任何一方的令牌和连接令牌将“my”与“_”和“3”组合在一起,从而产生如下结果:mine_3

这是期望的结果。

如果我们看一下最初的问题,代码(修改为使用‘my’而不是‘SomeFunction’):#define VARIABLE 3#define NAME(fun) fun ## _ ## VARIABLENAME(mine)

关于名字的论点显然是“我的”,而且已经完全扩展了。

按照6.10.3.3的规则,我们认为:mine ## _ ## VARIABLE

当##运算符被删除,映射到:mine_VARIABLE

和问题中的报道完全一样。

传统C预处理器对于没有令牌粘贴操作符的传统C预处理程序,有什么方法可以做到吗?##?

也许,也许不是-这取决于预处理程序。标准预处理器的优点之一是它具有可靠工作的功能,而对于预标准的预处理器则有不同的实现。一个要求是,当预处理器替换一个注释时,它不会像ANSI预处理器所要求的那样生成一个空间。GCC(6.3.0)C预处理器满足这一要求;XCode 8.2.1中的Clang预处理器不满足这一要求。

当它起作用时,它就完成了(x-paste.c):#define VARIABLE 3#define PASTE2(x,y) x/**/y#define EVALUATOR(x,y) PASTE2(PASTE2(x,_),y)#define NAME(fun) EVALUATOR(fun,VARIABLE)

extern void NAME(mine)(char *x);

请注意,在fun,和VARIABLE-这很重要,因为如果存在,则会将其复制到输出中,而您的结果是mine_ 3作为名称,当然,这在语法上是无效的。(现在,请把头发还给我好吗?)

GCC 6.3.0(跑步)cpp -traditional x-paste.c),我明白:# 1 "x-paste.c"# 1 ""# 1 ""# 1 "x-paste.c"extern void mine_3(char *x);

使用XCode 8.2.1中的Clang,我得到:# 1 "x-paste.c"# 1 "" 1# 1 "" 3# 329 "" 3# 1 "" 1# 1 "" 2# 1 "x-paste.c"

2extern void mine _ 3(char *x);

那些空间破坏了一切。我注意到这两个预处理器都是正确的;不同的预标准预处理器显示了这两种行为,这使得令牌粘贴在尝试移植代码时非常烦人和不可靠。标准##符号从根本上简化了这一点。

也许还有其他方法可以做到这一点。然而,这是行不通的:#define VARIABLE 3#define PASTER(x,y) x/**/_/**/y#define EVALUATOR(x,y) PASTER(x,y)#define NAME(fun) EVALUATOR(fun,VARIABLE)extern

void NAME(mine)(char *x);

GCC:# 1 "x-paste.c"# 1 ""# 1 ""# 1 "x-paste.c"extern void mine_VARIABLE(char *x);

接近但没有骰子。YMMV,当然,取决于您使用的预标准预处理器。坦率地说,如果您被一个不合作的预处理器困住了,那么安排使用标准C预处理器代替预标准处理器(通常有一种适当配置编译器的方法)可能比花很多时间想出一种方法来完成这一工作要简单得多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值