Search code examples
ccompilationc-preprocessorpragma

preprocessor macro stringify


im trying to understand preprocessor.

why one of the bellow preprocessor macro doesn't work while the other does

what is the difference between #pragma and _Pragma

why do we wrap STRINGZ with ASTRINGZ?

enter image description here

#define STRINGZ(x)                                #x
#define ASTRINGZ(x)                               STRINGZ(x)

#define DO_PRAGMA(x) _Pragma (#x)
#define TODO(x) DO_PRAGMA(message ("TODO - " #x))
#define msg(s) TODO( s " - @ - " ASTRINGZ(__FILE__))

msg ("This doesnt work")
#pragma message "but this does: " ASTRINGZ(__FILE__) 

sources:

https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html

http://forums.codeguru.com/showthread.php?215151-LINE-MACRO-to-string-literal&p=613574#post613574


Solution

  • why one of the bellow preprocessor macro doesn't work while the other does

    While the preprocessor will expand most further macros that result out of a current expansion, it will only do a single expansion step. So ASTRINGZ(__FILE__) is not going to be expanded all the way before being passed to the stringification of TODO.

    You have several options to deal with this, the easiest is to rely on the fact __FILE__ is already a string literal.

    #define msg(s) TODO( s " - @ - " __FILE__)
    

    But if you wish to experiment with macro expansion, you can try a deferring technique. This will delay the moment TODO is actually expanded itself, and give the arguments time to be expanded themselves.

    #define EMPTY() 
    #define DEFER(m) m EMPTY EMPTY()()
    
    #define msg(s) DEFER(TODO)( s " - @ - " ASTRINGZ(__FILE__))
    

    The above makes the ( s " - @ - " ASTRINGZ(__FILE__)) not be arguments to a macro, so ASTRINGZ will be expanded. DEFER(TODO) is a macro however, so it will be expanded to TODO EMPTY EMPTY()(). It will take two more expansion cycles (each EMPTY() for TODO (...) to be handed back to the preprocessor. At which point everything should be properly expanded.

    what is the difference between #pragma and _Pragma

    _Pragma is another standard way to provide compiler specific pragma directive. The difference is that _Pragma can be the result of macro expansion, while #pragma being a directive may not.

    why do we wrap STRINGZ with ASTRINGZ?

    It's another deferral technique. In case the argument to ASTRINGZ is itself the result of some non-trivial preprocssor expansion.