Undesired Macroprocessor Extension C

I use the unit test structure, which relies on the REQUIRE macro to execute statements.

Simplified, the macro works as follows:

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

Which is defined similarly to this:

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

PerformAssertion first two parameters are of type: const char* . The reason for the second parameter ( #expr ) is that the exact expression that was declared can be registered. This is the problem. The preprocessor extends the expression before it is passed as const char * , so it is not the same expression that was originally approved.

For instance:

 REQUIRE( foo != NULL ); 

The result of this call:

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

As you can see, the expression is partially extended, for example. the expression foo != NULL appears in the log as foo != 0 . NULL (which is a macro defined as 0 ) was extended by the C preprocessor before creating the message body with the statements. Is there a way to ignore or bypass the extension for message text?

EDIT: here's a solution for anyone curious:

 #define REQUIRE( expr ) INTERNAL_REQUIRE( expr, #expr, "REQUIRE" ) #define INTERNAL_REQUIRE( expr, exprString, macroName ) \ PerformAssertion( macroName, exprString, expr ); 
+6
source share
2 answers

Try making a string before calling an internal query. Your problem is that it is passed to the internal request in the second extension, which extends NULL. If you do this before, for example, In the require macro, it will not extend NULL.

+5
source

Here's what happens: since the macro, where the "stringization" # operator is used, is secondary, the sequence of operations works as follows:

  • The preprocessor identifies the REQUIRE(NULL) arguments and performs the replacement of the arguments in accordance with C 6.10.3.1. At this point, the replacement looks like INTERNAL_REQUIRE( 0, "REQUIRE" ) , because NULL expands as 0 .
  • The preprocessor continues to expand the macro chain with INTERNAL_REQUIRE ; at the moment, the fact that the macro was called using NULL is lost: in relation to the preprocessor, the expression passed to INTERNAL_REQUIRE is 0 .

The key to solving this problem is this paragraph from the standard:

A parameter in the substitution list, unless the preprocessor token # or ## precedes or is followed by the preprocessing token ## (see below), is replaced with the corresponding argument after all the macros contained in it have been expanded.

This means that if you want to write an exact expression, you need to do this at the very first level of macro expansion.

+2
source

Source: https://habr.com/ru/post/918502/


All Articles