【发布时间】:2016-06-25 19:53:47
【问题描述】:
我想知道为什么我们不能在defines 之外使用令牌连接。
当我同时想要这些时,就会出现这种情况:
- 库中的无冲突命名(或“泛型”)
- 可调试性;当为此使用
define时,整个代码将合并为一行,调试器将仅显示使用define的行
有些人可能想要一个例子(实际问题在下面):
lib.inc:
#ifndef NAME
#error includer should first define NAME
#endif
void NAME() { // works
}
// void NAME##Init() { // doesn't work
// }
main.c:
#define NAME conflictfree
#include "lib.inc"
int main(void) {
conflictfree();
// conflictfreeInit();
return 0;
}
错误:
In file included from main.c:2:0:
lib.h:6:10: error: stray '##' in program
void NAME##Init();
^
经验法则是“仅在定义中连接”。如果我没记错的话:原因是因为预处理器阶段。
问题:为什么它不起作用。阶段参数听起来像是曾经是实施限制(而不是逻辑原因),然后进入标准。如果NAME() 工作正常,接受NAME##Init() 会有什么困难?
【问题讨论】:
-
嗯,很天真的事情是预处理器指令总是开始以
#.. 我猜预处理器开发人员只是懒得解析其他东西。 -
如果你能说服 C 委员会接受它,它可能会起作用。但是
NAME##Init与#define NAME_(x) NAME##x加上NAME_(Init)的优势可能并不值得。 -
@EugeneSh.: 但是当使用宏时,预处理器必须读取所有代码来识别和替换。该提案只会将其扩展到相邻的
##。 -
@Peter 这经常用于“通用”C 库中。查看任何通用库,您将看到该模式。用户可能会编写 DEF(Foo, int) 和 DEF(Bar, void*) 并获得两个处理不同数据类型的不同函数。
-
我认为最接近答案的可能是 C 标准基本原理中关于## 的这一行:“这些原则编纂了现有技术的基本特征,并且与字符串化运算符的规范一致。 "委员会试图不向尚未广泛使用的语言添加新功能;他们有时会更改语法以减少出错的可能性。
标签: c c-preprocessor