6

我正在使用一个依赖REQUIRE宏来执行断言的单元测试框架。

简化后,宏的工作方式如下:

#define REQUIRE( expr ) INTERNAL_REQUIRE( expr, "REQUIRE" )

其定义类似于:

#define INTERNAL_REQUIRE( expr, macroName ) \
PerformAssertion( macroName, #expr, expr );

PerformAssertion的前两个参数的类型为:const char*. 第二个参数 ( #expr) 的原因是可以记录断言的确切表达式。这就是问题所在。预处理器在将表达式作为 a 传递之前对其进行扩展const char *,因此它与最初断言的表达式不同。

例如:

REQUIRE( foo != NULL );

将导致此调用:

PerformAssertion( "REQUIRE", "foo != 0", foo != 0 );

如您所见,表达式被部分扩展,例如表达式foo != NULL在日志中显示为foo != 0. 在构建断言消息文本之前,C 预处理器扩展了NULL(定义为 be 的宏)。0有没有办法可以忽略或绕过消息文本的扩展?

编辑:对于任何好奇的人来说,这是解决方案:

#define REQUIRE( expr ) INTERNAL_REQUIRE( expr, #expr, "REQUIRE" )

#define INTERNAL_REQUIRE( expr, exprString, macroName ) \
PerformAssertion( macroName, exprString, expr );
4

2 回答 2

5

尝试在调用内部要求之前进行字符串化。您的问题是它在扩展 NULL 的第二次扩展中传递给内部要求。如果您在此之前进行字符串化,例如在 require 宏中,它不会扩展 NULL。

于 2012-06-19T17:23:13.917 回答
2

这是正在发生的事情:由于应用“字符串化”运算符的宏#是二级宏,因此操作顺序如下:

  • 预处理器根据 C 6.10.3.1识别参数REQUIRE(NULL)并执行参数替换。此时,替换看起来像INTERNAL_REQUIRE( 0, "REQUIRE" ),因为NULL被扩展为0
  • 预处理器继续扩展宏链INTERNAL_REQUIRE;在这一点上,宏已经被调用的事实NULL丢失了:就预处理器而言,传递给的表达式INTERNAL_REQUIRE0

解决此问题的关键在于标准的本段:

替换列表中的参数,除非前面有 # 或 ## 预处理标记或后跟 ## 预处理标记(见下文),在其中包含的所有宏都已展开后,将替换为相应的参数。

这意味着,如果您想捕获精确的表达式,您需要在宏扩展的第一级进行。

于 2012-06-19T17:45:47.847 回答