[英]Unwanted C Preprocessor Macro Expansion
I'm using a unit test framework that relies on a REQUIRE
macro for performing assertions. 我正在使用一个单元测试框架,它依赖于
REQUIRE
宏来执行断言。
Simplified, the macro works like this: 简化后,宏的工作原理如下:
#define REQUIRE( expr ) INTERNAL_REQUIRE( expr, "REQUIRE" )
Which is defined similar to this: 其定义与此类似:
#define INTERNAL_REQUIRE( expr, macroName ) \
PerformAssertion( macroName, #expr, expr );
PerformAssertion
's first two parameters are of the type: const char*
. PerformAssertion
的前两个参数类型为: const char*
。 The reason for the second parameter ( #expr
) is so the exact expression that was asserted can be logged. 第二个参数(
#expr
)的原因是可以记录断言的确切表达式。 This is where the issue lies. 这就是问题所在。 The preprocessor expands the expression before it is passed as a
const char *
, so it's not the same expression that was originally asserted. 预处理器在将表达式作为
const char *
传递之前扩展表达式,因此它与最初声明的表达式不同。
For instance: 例如:
REQUIRE( foo != NULL );
Would result in this call: 会导致此次通话:
PerformAssertion( "REQUIRE", "foo != 0", foo != 0 );
As you can see, the expression is partially expanded, eg the expression foo != NULL
appears in the log as foo != 0
. 如您所见,表达式部分展开,例如表达式
foo != NULL
在日志中显示为foo != 0
。 The NULL
(which is a macro defined to be 0
) was expanded by the C preprocessor before building the assertions message text. 在构建断言消息文本之前,C预处理器扩展了
NULL
(这是一个定义为0
的宏)。 Is there a way I can ignore or bypass the expansion for the message text? 有没有办法可以忽略或绕过消息文本的扩展?
EDIT: Here's the solution, for anyone curious: 编辑:这是解决方案,对任何好奇的人:
#define REQUIRE( expr ) INTERNAL_REQUIRE( expr, #expr, "REQUIRE" )
#define INTERNAL_REQUIRE( expr, exprString, macroName ) \
PerformAssertion( macroName, exprString, expr );
Try making the stringifying before the call to the internal require. 尝试在调用内部require之前进行字符串化。 Your problem is that it is passed to internal require in the second expansion which expands NULL.
您的问题是它在第二次扩展中传递给内部require,它扩展了NULL。 If you make the stringifying happen before that, eg In the require macro, it will not expand the NULL.
如果在此之前进行字符串化,例如在require宏中,它将不会扩展NULL。
Here is what's going on: since you macro where the "stringization" operator #
is applied is second-level, the sequence of operations works as follows: 这是正在发生的事情:因为您应用“stringization”运算符
#
宏是二级的,所以操作序列的工作方式如下:
REQUIRE(NULL)
and performs argument substitution as per C 6.10.3.1. REQUIRE(NULL)
的参数,并根据C 6.10.3.1执行参数替换 。 At this point, the replacement looks like INTERNAL_REQUIRE( 0, "REQUIRE" )
, because NULL
is expanded as 0
. INTERNAL_REQUIRE( 0, "REQUIRE" )
,因为NULL
扩展为0
。 INTERNAL_REQUIRE
; INTERNAL_REQUIRE
扩展宏链; at this point, the fact that the macro has been called with NULL
is lost: as far as the preprocessor is concerned, the expression passed to INTERNAL_REQUIRE
is 0
. NULL
调用的事实将丢失:就预处理器而言,传递给INTERNAL_REQUIRE
的表达式为0
。 A key to solving this problem is in this paragraph from the standard: 解决这个问题的关键在于本段标准:
A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded.
替换列表中的参数除非前面带有#或##预处理标记或后跟##预处理标记(见下文),否则在扩展其中包含的所有宏之后,相应的参数将替换该参数。
This means that if you would like to capture the exact expression, you need to do it in the very first level of the macro expansion. 这意味着如果您想捕获精确的表达式,则需要在宏扩展的第一级执行此操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.