9

The argument of _Pragma is a string so I would think that when you paste strings together in the normal c-preprocessor way (ie putting them right next to eachother) that you could form a new string for the argument of _Pragma. However

_Pragma("GCC Poison " "puts")

fails with the error

error: _Pragma takes a parenthesized string literal

How can this be circumvented?

This particular example isn't very useful and has a trivial solution of making them all one string to begin with, but the end goal is to stringize a macro into it

rtpax
  • 1,687
  • 1
  • 18
  • 32
  • 2
    A `DO_PRAGMA` macro as [here](https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html) ? – Eugene Sh. Aug 18 '17 at 17:52
  • Did you try `_Pragma("GCC Poison ""puts")`? – Yunnosch Aug 18 '17 at 17:55
  • @Yunnosch Yes, It also fails. @ Eugene Sh. That `DO_MACRO` is promising, I've still got to test whats possible – rtpax Aug 18 '17 at 17:57
  • Could "parenthesized string literal" mean "(blabla)"? – Yunnosch Aug 18 '17 at 17:59
  • @Yunnosch, no that does not work. Also, literally putting _Pragma("GCC poison puts") does work – rtpax Aug 18 '17 at 18:09
  • @EugenSh. Wrapping `DO_PRAGMA` in a second macro to allow expansion of the original value got it to work exactly as I was hoping, thanks for the great suggestion – rtpax Aug 18 '17 at 18:10
  • 1
    FYI, there's no such thing as string literal concatenation as far as the preprocessor is concerned. In particular, the C preprocessor runs in translation phase 4; string literal concatenation is a translation phase 6 feature. – H Walters Aug 19 '17 at 02:39

1 Answers1

8

The DO_PRAGMA macro in the GNU docs is defined like this

#define DO_PRAGMA(x) _Pragma (#x)

Using this, if you put two seperate token unstringized next to eachother, they will become stringized. To expand macros within the definition, it must go through one level of indirection, so define as

#define DO_PRAGMA_(x) _Pragma (#x)
#define DO_PRAGMA(x) DO_PRAGMA_(x)

Using this you can create shorthands for various pragmas like this

#define POISON(name) DO_PRAGMA(GCC poison name)

POISON(puts) // becomes _Pragma("GCC poison puts")

Thanks to Eugene Sh. for pointing me to the DO_PRAGMA macro

Iulian Onofrei
  • 9,188
  • 10
  • 67
  • 113
rtpax
  • 1,687
  • 1
  • 18
  • 32
  • Is it even possible to escape a more complex pragma expression, such as `DO_PRAGMA("comment(linker, \"/EXPORT:" #alias "=" #func "\")")` ? I'm trying to wrap my head around this, but can't find a solution; indirections as provided in the answer don't work, because linker command itself is wrapped in quotes that can be escaped inside string, but can't outside, i.e. you can't simply do `DO_PRAGMA(comment(linker, \"/EXPORT: #alias = #func \"))`. – Marandil Dec 17 '21 at 01:57
  • @Marandil To escape quotes within quotes within quotes in c, the escapes get exponentially larger at each step as you reduce (//) to (/) and (/") to ("). So you have " -> /" -> ///" -> ///////" and so on. – rtpax Dec 17 '21 at 15:27
  • I'm not entirely clear on what you want the quotes to be doing in the example you gave, but you probably don't want the outside quotes as it will be stringized. So maybe something like `DO_PRAGMA(comment(linker, "/EXPORT:\" #alias \"=\" #func \""))` – rtpax Dec 17 '21 at 15:35
  • say I want to create a macro `ALIAS(alias, func)` that given two symbols (say `foo` and `bar`) produces `_Pragma("comment(linker, \"/EXPORT:foo=bar\")")` which would be equivalent to `#pragma comment(linker, "/EXPORT:foo=bar")` with pragma as preprocessor directive. – Marandil Dec 17 '21 at 21:30
  • 1
    Alright, I think I found a solution with a total of 4 layers of macros. I didn't think about it at first, but all I had to do was to create both strings using the `#` operator. `#define API_ALIAS_NESTED_3(part) _Pragma(#part)` then `#define API_ALIAS_NESTED_2(part) API_ALIAS_NESTED_3(comment(linker, part))`, `#define API_ALIAS_NESTED_1(part) API_ALIAS_NESTED_2(#part)` and finally `#define API_ALIAS(alias, func) API_ALIAS_NESTED_1(/EXPORT:alias=func)`. Thanks for the inspiration! – Marandil Dec 17 '21 at 21:55