9

I need help doing the following:

a preprocessor macro label(x) shall output "#x", e.g.,

#define label(x) ...

if I call label(aname), the output shall be "#aname" (w/o quotes)

I know, that the following tries were errors.

#define label(x) #x   // leads to "x"
#define label(x) \#x  // is \"x"
#define label(x) "#x" // is "#x" (but not the content of x") "#otto"

It may exist a kind of escaped # (pound), but I don't know, how to escape...

Edit: I run "gcc -E test -o test.html" to get the output. The point is: How do I print out a hash mark (#) with a makro only using preprocessor's capabilities?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
tuergeist
  • 9,171
  • 3
  • 37
  • 58
  • 1
    May I ask what you're trying to do? – Chris Lutz Sep 06 '09 at 20:12
  • *g* yes. I'll use the preprocessor to "create" html code ;) label(x) shall be used to create a link to an anchor, e.g., ... I reduced the complexity for the question. – tuergeist Sep 06 '09 at 20:14
  • Do you want this HTML code as a string, for use in a C program, or as actual HTML code, to go straight to the browser? – Chris Lutz Sep 06 '09 at 20:16
  • as actual HTML code, to go straight to the browser or to save in a file. No #define label(x) printf("#%s", x) ;) – tuergeist Sep 06 '09 at 20:21
  • 3
    May I suggest in this case that the C preprocessor is the wrong tool for the job? It's not a powerful text processor. It is designed for the C language, and works great in that language, and rather poorly if you try to use it for much else. You're going to be fighting an uphill battle to get it to do things. This is a fine example - I'm not even sure if you can even do what you want here. – Chris Lutz Sep 06 '09 at 20:29
  • @Chris: suggestion is noticed, but not the answer to the question. I may accept an "I is not possible with the c preprocessor" ;) – tuergeist Sep 06 '09 at 20:35
  • I can't definitively say whether or not it's possible at this point, but I'll look into it. – Chris Lutz Sep 06 '09 at 20:36
  • 1
    This is actually quite useful if you want to use the C preprocessor to generate Haskell unboxed tuples, which are mangled with hashes. – Edward Kmett Mar 18 '10 at 21:13

5 Answers5

13

The answer is:

#define hash #
#define f(x) x
#define label(a) f(hash)a

then

label(foobar)

creates

#foobar

I found it with the help of all of you, but especially wintermute. Thanks a lot!

(Using gcc 4.3.3)

tuergeist
  • 9,171
  • 3
  • 37
  • 58
  • but that's no answer to your question: you asked for the quoted expression `"#foobar"` – Christoph Sep 06 '09 at 21:17
  • Is this well-defined, or a function of the specific preprocessor implementation tuergeist is using? – bdonlan Sep 06 '09 at 21:17
  • I just want to say that, someday soon, you may find yourself coming back here and asking another question about how to get the C preprocessor to do X or Y. I hope you'll remember what I said about this being an uphill battle, and that you strongly consider my recommendation to find a new tool for this job. – Chris Lutz Sep 06 '09 at 21:21
  • @christoph: I only used the quotes to make clear whats the output, sorry – tuergeist Sep 06 '09 at 21:21
  • @Chris: I won't come back to ask preprocessor questions. I swear it. I had to use stuff from other people :( Those people thought that it was a good idea to use the preprocessor and I was not allowed to change to another tool. I really appreciate your answer. – tuergeist Sep 06 '09 at 21:24
  • 1
    @tuergeist: well, that makes things easier ;) I'd suggest using backticks to mark the output as code instead of double quotes - that would have prevented my misunderstanding – Christoph Sep 06 '09 at 21:26
  • 1
    @tuergeist - Ah, the classic "maintaining someone else's clever hack" conundrum. I apologize on behalf of whoever had the "brilliant" idea to generate HTML with the C preprocessor. – Chris Lutz Sep 06 '09 at 21:28
  • @ALL: I'll upvote all answer you supported this question.. Thank you and good night. – tuergeist Sep 06 '09 at 21:30
  • This is very cool but sadly the preprocessor only runs once. This can't be used to write more defines – Steven Lu Jan 03 '14 at 23:36
  • Speaking about bad ideas, I am currently looking at this to be able to generate C# code with `#nullable enable` using the `gcc` preprocessor... ;) – Per Lundberg Nov 18 '21 at 20:04
4

I don't think you can, which is not wholly unreasonable since the output of the C preprocessor should not produce an unquoted '#' because that would indicate a pre-processor directive, and you cannot generate pre-processor directives on the fly like that.

In other words, the C preprocessor is a preprocessor for C (and C++) and not a completely general purpose tool.

Either use an alternative macro processor (m4 is the standard recommendation on Unix-like systems), or go about things differently.

For example, have the macro replacement:

#define label(x)    !@!x

Then post-process the output replacing '!@!' with '#'.

(The imake program uses a similar stunt; the C preprocessor does most of the work, but its output doesn't preserve line breaks needed by 'make', so 'imake' uses the notation '@@\' or thereabouts to indicate where line breaks need to be inserted after the C preprocessor has done its worst.)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
4

You can do something like this:

#define f(x) x
#define label(a) f(#)a

I tested this by running it directly through cpp (the C preprocessor) instead of through gcc. Example:

cpp test > test.html

Using the cpp that is part of gcc version 4.0.1.

The only problem I noticed is that I get some extra unwanted output, namely the first 4 lines of the file are as follows:

# 1 "test"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "test"
E.M.
  • 4,498
  • 2
  • 23
  • 30
3

String literals in C will be concatenated, so you can do

#define label(x) "#" #x

I don't think it's possible without string concatenation (ie without invoking the C compiler as you want to do):

You can do some fancy stuff with additional levels of indirection and I even got the preprocessor to generate the desired output via

#define hash #
#define quote(x) #x
#define in_between(c, d) quote(c ## d)
#define join(c, d) in_between(c, d)
#define label(x) join(hash, x)
label(foo)

The problem is it will also generate an error message as in_between() expands to #foo, which is not an valid preprocessor token. I don't see any way around this.

My advise would be to choose the right tool for the job: switch to another macro language like m4 or even ML/I if you feel adventurous or use a scripting language like PHP or Perl. GPP seems nice as well and might be a better fit.

Christoph
  • 164,997
  • 36
  • 182
  • 240
  • leads to '"#" "string"' which is not '#string' may I ask how do you tested your answer? – tuergeist Sep 06 '09 at 20:20
  • In the C language, writing `char *c = "#" "string";` is identical to writing `char *c = "#string";` - the language concatenates string literals that are next to each other. Thus, this doesn't work with the preprocessor along, but does work with the C language. – Chris Lutz Sep 06 '09 at 20:32
  • As I wrote, I'll use the preprocessor's output, no additional c compiler will run. – tuergeist Sep 06 '09 at 20:35
1

Try:

#define label(x) "#"x
Neil
  • 2,378
  • 1
  • 20
  • 28