绕过#define'd 宏?
Posted
技术标签:
【中文标题】绕过#define\'d 宏?【英文标题】:Bypassing a #define'd macro?绕过#define'd 宏? 【发布时间】:2014-09-12 17:05:24 【问题描述】:假设你有宏
#define TOKEN1 <arbitrary sequence of characters>
但是假设,在某些情况下,您的真正意思是 TOKEN1,而不是它的定义。有没有一个技巧可以让预处理文件包含“TOKEN1”,而不用#undef'ining TOKEN1,并且在#define'd之后出现TOKEN1?
上下文:
我正在通过重新定义new
来添加内存跟踪。但是,我遇到了一个问题,我在几个类中也重载了operator new
,并且不得不在所有这些地方取消定义 new ,然后重新包含具有魔力的标头是很尴尬的。
【问题讨论】:
没办法,在编译之前预处理器会盲目地替换文本,所以如果你不#undef
它,你不能要求编译器忽略预处理器。
@vsoftco 没有办法编写一个评估为 TOKEN1 的宏,而预处理器不会评估它?
好吧,我猜你可以做#define TOKEN2 TOKEN1
,然后当你写TOKEN1
时,预处理器会用TOKEN2
替换它,然后用TOKEN1
替换它,此时它将停止替换...
@T.C.:看起来你在我回答的同时发表了这条评论。请注意,只要 TOKEN2
尚未重新定义为其他内容,它就可以工作。
因此对于宏和实际语言标识符使用不同命名约定的通用编码约定。
【参考方案1】:
一般的方法是将所有需要“不替换 TOKEN1”的代码放入一个单独的源文件中,然后不将定义替换的头文件包含在该文件中。
如果任意字符序列是单个标记(就像在您编辑问题之前一样),您可以这样做:
#define TOKEN2 TOKEN1
if (you_really_mean(TOKEN1))
//...
#undef TOKEN2
但是,这个解决方案是有限的,因为如果 TOKEN2
之前已经被重新定义为其他东西,你就会遇到问题。
如果您可以完全控制定义的内容和不定义的内容,您可以这样做:
#define TOKEN1 TOKEN2
#define TOKEN2 <arbitrary sequence formerly assigned to TOKEN1>
然后,在你的代码中转义TOKEN1
:
#undef TOKEN1
//... code where you don't want TOKEN1 replaced
#define TOKEN1 TOKEN2
对于您处理重载new
的特殊问题,我发现在很大程度上,重载new
实现大多相同(因为它们通常只是样板代码,将分配器更改为使用系统堆以外的东西)。如果您也是这种情况,您可以将重载定义放入无保护的头文件中。这个头文件可以#undef
定义new
然后重载定义后再重新定义。
那么任何类都可以包含这个头文件。
【讨论】:
另一种方法是要求项目使用除new
之外的某种机制来分配内存,并且该机制具有您的调试功能。然后您可以尝试禁用常规new
分配器的用户。见this question。【参考方案2】:
如果你可以访问语言扩展,a GCC/Clang extension 可以做这样的事情(我认为 MSVC 也有类似的):
#define TOKEN1 123
#pragma push_macro("TOKEN1")
#undef TOKEN1
TOKEN1 // inserts TOKEN1 into the program text
#pragma pop_macro("TOKEN1")
TOKEN1 // inserts 123 into the program source text
它允许您独立于输入文本保存和恢复宏定义,仅用于此目的。
不过,jxh 的解决方案更简洁;但从根本上说,您应该重新考虑尝试使单个术语具有多种含义的原因。宏语言应该帮助您抽象单个统一程序的元素;不要在一个文件中创建两个相互竞争的战斗源。
【讨论】:
【参考方案3】:如果<arbitrary sequence of characters>
作为宏调用有效(它具有标识符或id( args )
的形式),您可以通过添加“反向”宏暂时绕过定义。
#define TOKEN1 arbitrary_identifier
TOKEN1 // expands to arbitrary_identifier
...
// Now we really want to say TOKEN1
#define arbitrary_identifier TOKEN1
TOKEN1 // TOKEN1 => arbitrary_identifier => TOKEN1 and stop expanding
// Finished with TOKEN1 override
#undef arbitrary_identifier
TOKEN1 // expands to arbitrary_identifier again.
我认为对于真正任意的扩展标记序列不存在解决方法。而且,这种变通方法确实不比#undef TOKEN1
再做#define
好,因为绕过代码仍然需要知道扩展。
【讨论】:
【参考方案4】:如果您有权更改 TOKEN1 的定义,您可以这样做:
#define TOKEN1() arbitrary stuff...
然后TOKEN1
后面没有(
不会进行扩展。即使有追随者(
,您仍然可以通过写(TOKEN1)
来压制它。
【讨论】:
以上是关于绕过#define'd 宏?的主要内容,如果未能解决你的问题,请参考以下文章