36

Is there a way in gcc/g++ 4.* to write a macro that expands into several lines?

The following code:

#define A X \ Y

Expands into

X Y

I need a macro expanding into

X
Y
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Michael Rybak
  • 361
  • 1
  • 3
  • 3
  • 6
    Interesting question - I'm unaware of a way to do what you're describing in C/C++ (though maybe GCC has an extension I'm unfamiliar with). Can you explain what you're trying to do in a little more detail (in terms of the 'what' , not the 'how')- there may be another way to get the result you're ultimately looking for. – Michael Burr Feb 16 '10 at 06:55
  • 5
    My motivation would be that this makes debugging easier. – Potatoswatter Apr 02 '10 at 14:49
  • @JonathanLeffler I don't see the use of marking *this* question as duplicated, when it's the only one with viable answers. – Antonio Apr 12 '17 at 08:31
  • 1
    This is especially unfortunate since non-logged-in users automatically get redirected to the other one, so they get the question without the good answers. – etarion Oct 07 '19 at 13:25

8 Answers8

33

Got it!

#define anlb /*
*/ A /*
*/ B

anlb anlb

Down arrow

gcc -E -CC nl.c

Down arrow

/*
*/ A /*
*/ B /*
*/ A /*
*/ B
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • 3
    Nice trick. I tried it with VC++; while its preprocessor can be instructed to preserve comments in the preprocessor output using `/C`, it doesn't preserve comments in macros, so this all ends up on one line. – James McNellis Apr 23 '10 at 21:04
  • 2
    Which version worked with this? The latest `g++` certainly doesn't seem to. (Which is a shame, given the macro I'm working with at the moment.) – underscore_d Jan 03 '16 at 20:41
  • 1
    @underscore_d I just tested with GCC 5.1 and Clang 3.6, which are the latest I have. Are you sure the `-CC` argument got through to the compiler? – Potatoswatter Jan 06 '16 at 15:34
  • Yeah, I probably just forgot to type that or something... I'll try again soon! – underscore_d Jan 07 '16 at 16:01
  • What are the two "V"s for? If it is for separation of the code blocks, ` ` may also work. – Peter Mortensen Feb 04 '16 at 19:53
  • 2
    Indeed the `-CC` is crucial. [-CC is ***Do not discard comments, including during macro expansion***](http://linux.die.net/man/1/gcc). – Peter Mortensen Feb 04 '16 at 19:54
  • @PeterMortensen They are intended as down arrows. Feel free to click "edit." – Potatoswatter Feb 05 '16 at 00:48
  • Unfortunately, this doesn't seem to make \__LINE\__ advance! – Michael Feb 05 '16 at 03:22
  • 1
    @Potatoswatter: I have replaced the "V"s with images of down arrows (made for the occasion). Feel free to revert. – Peter Mortensen Feb 05 '16 at 12:58
  • @Michael `__LINE__` is specified to reflect the position in the source file, so it can't advance inside a macro. You can try preprocessing and compiling the file in separate invocations of GCC. I can't recall whether it has an option to generate `#line` directives. There's an entire manual dedicated to the GCC preprocessor, which you might check into. – Potatoswatter Feb 05 '16 at 15:01
  • For Xcode users, add flag "-CC" to "Other Warning Flag" field in the project's Build Settings to keep the comment. Hats off to the @Potatoswatter for the trick :P – David Andreoletti Oct 15 '16 at 06:25
9

Make the macro generate a special markup, say __CR__, then pipe the result of CPP into a script which translates the macro to a true newline, for example, sed 's/__CR__/\n/g'.

I just found this useful to generate a code pattern to be filled by hand. It is quite easier when the code is readable.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Eric Dujardin
  • 91
  • 1
  • 1
6

You can just put a magic character sequence in the macro, e.g.

#define X(y,z) y nl z

run gcc -E infile | sed g/s/nl/\n/ > whatever

(Maybe not exactly right, but you get the idea, right? Pipe it through sed or tr or run Emacs on the output.)

I do this sometimes to use C macros to generate source code and no I don't want to learn how to do it in Perl or M4 or yet another tool.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bart Simpson
  • 61
  • 1
  • 1
3

Putting a side the fact that not being able to put newlines in macros create unreadable code, making it harder to debug preprocessor outputs. It is true that C and C++ might not care about newlines, but the C preprocessor does.

I would really like to make a macro ConditionalDefine(x,y) that outputs the following.

    #ifdef x
    #define y
    #endif

The following defines do something close:

    #define hash #
    #define nl
    #define _def_p8(A,B) A ifdef _P8_K60_BOARD_ A define B  A endif
    #define X_def_p8(A,B) _def_p8(A,B)
    #define def_p8(A) X_def_p8(nl hash,A)

expanding the following:

    def_p8(PTPD_DBGA 0)

results in:

    # ifdef _P8_K60_BOARD_ # define PTPD_DBGA 0    # endif

But without being able to put new lines in before the hashes it would not work as intended. It is also annoying the hoops you have to jump through just to get that close.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 2
    Even if you form the text of a preprocessor directive using a macro, it won't be executed. What you can do is put the lines to be replicated into a header and use a "computed" `#include STRINGIZE( blah( xyz ) )` directive. You still can't compute macro names, but it's the only option. Maybe check the Boost Preprocessor library (but I've never gotten into it). – Potatoswatter Jun 16 '13 at 00:27
2

I'm pretty sure CPP, being designed for C which doesn't care for newlines, and all, can't handle this kind of work. Still you can mark wanted newlines with some special marker string and pass the result through sed or awk to get what you want.

SF.
  • 13,549
  • 14
  • 71
  • 107
  • C doesn't care for tabs either, but you can define a macro whose expansion includes one or more tabs. Lack of newlines is a very specific hole in C macro capability. – Steve Jessop Feb 16 '10 at 09:16
  • 1
    @Steve Jessop: if you need a general macro preprocessor, use 'm4'. The C pre-processor is designed to meet the needs of the C compiler; it is not, despite its widespread use, a general-purpose macro preprocessor. – Jonathan Leffler Feb 16 '10 at 15:03
  • 2
    Is the tab preservation guaranteed by the standard or merely allowed implementation? The preprocessor operates on sequences of tokens, while comments, tab characters and newlines are counted as white-space, not preprocessing tokens. I don't see anything in the standard that suggests white space needs to be preserved in replacement lists, only preprocessing tokens. – jw013 Apr 02 '13 at 22:27
  • @jw013: I'm not sure if it's a standard in general but I'm absolutely sure it must preserve tabs and other whitespaces in string literals. I seriously doubt anyone would go over headaches to recognize whether the replacement contains strings or not and remove/replace tabs only outside these strings. Think: `#define tab_or_spaces(x) ( (x)? " " : " " )` - why would the preprocessor try to go to determine where stripping tabs or spaces is allowed? – SF. Apr 02 '13 at 23:06
  • 5.1.1.2p1 of the C99 standard actually answered my question: whether the preprocessor needs to preserve white space between preprocessing tokens or not is implementation-defined. – jw013 Apr 03 '13 at 01:19
  • To answer your question, it's because the preprocessor language grammar as mandated by the standard requires it. Your question actually doesn't make much sense if you think about it. A string literal is a preprocessing token. `"#define tabs_or_spaces(x) ( (x)? '\t' : ' ' )"` is also a string literal. If the preprocessor needs to know the difference between a string literal and a `#define` directive, it also needs to know the difference between a string literal and white space that separates preprocessing tokens. – jw013 Apr 03 '13 at 01:20
  • 1
    "I seriously doubt anyone would go over headaches to recognize whether the replacement contains strings or not and remove/replace tabs only outside these strings." -- That's extraordinarily clueless. – Jim Balter Jul 17 '14 at 09:00
2

From the docs:

in the present implementation, the entire expansion comes out on one line

MSalters
  • 173,980
  • 10
  • 155
  • 350
1

Why does the spacing matter?

The imake program used in (older?) builds of X11 used the C pre-processor to generate makefiles, but imake program used a special technique of indicating line endings with @@ symbols at the ends of lines, and then post-processed the output of the pre-processor to replace the @@ symbols with newlines.

From this design, I conclude that there is no reliable way to obtain newlines from expanded macros in C (or C++). Indeed, for C, there is no need since:

  • C does not care about newlines compared with white space after the C pre-processor is run, and
  • You cannot generate pre-processor directives from macros etc.
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 3
    That's all nice and pretty as long as you're using `CPP` to produce C/C++/other newline-agnostic language result. Very recently I had to generate shell files using C Preprocessor. I assure you newlines matter. – SF. Feb 16 '10 at 08:51
  • 5
    @SF: In which case you are using the wrong tool for the job. The CPP is, um, the C preprocessor. As such, it follows some strict rules in the C standard, and is presumably optimized for preprocessing C. Get yourself a real macro preprocessor, or write something using a scripting language. Please do not insist that additional features be bolted onto software I use as intended. Similarly, I like being able to buy a crescent wrench that doesn't have a hammerhead attached to the side. – David Thornley Apr 02 '10 at 15:31
  • 6
    "Why does the spacing matter?" Sometimes a human has to troubleshoot the output :) – Kuba hasn't forgotten Monica Aug 12 '14 at 14:50
  • 2
    The CPP is the preprocessor used by gfortran. Fortran is sensitive to newlines and to line length. – P O'Conbhui Dec 12 '16 at 04:44
-5

Is this what you want:

#define A "X \nY"
Jagannath
  • 3,995
  • 26
  • 30
  • No, I don't need a string constant. I need A to expand into two operators separated by a line break. For instance #define A x++; __something special here__ y++; A And I'd expect it to expand into: x++; y++; Instead of x++; y++; – Michael Rybak Feb 16 '10 at 06:49
  • 4
    What's wrong with `x++; y++;`? The compiler doesn't care about whitespace. – Carl Norum Feb 16 '10 at 06:54
  • @Michael, Then what are trying to achieve – Narendra N Feb 16 '10 at 09:55