6

I want to define the following ordinary looking macro:

#define MY_ENUM enum MyEnum{ \
    myVal0, \ //Describes this situation
    myVal2  \ //Describes that situation
}

To my surprise this doesn't work due to error: stray ‘\’ in program. Even some whitespace after the backslash results in warning: backslash and newline separated by space. As this answer points out, the backslash must be the last character on the line. This answer points out that line splicing occurs before comments are processed. The reason why this order was chosen makes absolutely no sense to me; the only reason I can imagine this could be done is to allow multiline comments like the following:

//This is a comment which \
follows in the next line

Which looks extremely dangerous as such a thing could just eat up whatever code is on the next line when attempted. The reverse order, i.e replace each comment with single whitespace before splicing lines sounds like a much more sensible choice to me. Can someone explain why this choice was made?

I can work around my original problem with the following:

#define MY_ENUM enum MyEnum{ \
    myVal1, /*Describes this situation*/ \
    myVal2  /*Describes that situation*/ \
}

My purpose when doing this awkward enum macro definition is that this macro must be shared between c++ (where it absolutely must be a class member due to Qt) and c. Defining a macro such as this looks like the only solution to me but the above workaround looks ugly and I absolutely don't want to leave enums uncommented. Am I approaching this problem wrong?

Community
  • 1
  • 1
Ayberk Özgür
  • 4,986
  • 4
  • 38
  • 58
  • 3
    Pardon my naivete, but why do you need an enum macro? I would place the enum definition into a header file and include the header file. – Thomas Matthews Jun 07 '16 at 16:25
  • 5
    You've described the problem you ran into, and you've described the solution. Use `/*...*/` comments. – Pete Becker Jun 07 '16 at 16:34
  • 1
    It does sound like you're asking if you can write C code using non-C syntax because it'd look nicer... which is a little odd. – Dmitri Jun 07 '16 at 16:39
  • Notice, that even if comments were recognized before splicing, your code will still not work: comments are replaced with a space, so your `\` wouldn't be last character anyway. – Revolver_Ocelot Jun 07 '16 at 16:39
  • "... splicing occurs before comments are processed. This order makes absolutely no sense to me;" --> Its is called a **pre**-processor after all for it processes input _before_ evaluating it the C C++ code. – chux - Reinstate Monica Jun 07 '16 at 20:50
  • The reason for the enum macro: To be used in both c++ as a *member* enum and also in c. That's why I'm not able to define them regularly in a header and include in both places. I would like better solutions though. – Ayberk Özgür Jun 08 '16 at 07:25
  • @chux in this sense, comments are part of c code that must not be interpreted by the preprocessor. This makes no sense to me either, they are not part of code and they are not to be *interpreted* by anything other than a human. Am I thinking wrong? – Ayberk Özgür Jun 08 '16 at 07:28
  • Comments _are_ part of the C code. They act as white-spaces. Example:`-/*abc*/-a` is the same as code `- -a`, not `--a`. – chux - Reinstate Monica Jun 08 '16 at 14:46

2 Answers2

4

The problem is that the C preprocessor just adds another line ending character when the \ is hit and continued.

Within // comments you can't do that. The \ character isn't accepted to continue the comment (it's supposed to appear as a single line anyway).


The solution is—as you found out yourself—to use the /* */ comment style.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • 2
    The line splicing happens first, putting the whole macro definition including the comments on one line... so the first `//` comments out the remainder of the macro definition. With the `/* */` comments, the comment can be closed before the end of the line, which is why that style still works. – Dmitri Jun 07 '16 at 16:45
1

To understand this phenomenon, you may to refer into the C standard (I believe that C++ is similar to C in that manner). In particular it's in translation phases section (C11 draft §5.1.1.2).

The preprocessor is obligated to behave just like as the phases are executed in the top-down order (i.e. step 3 is executed after step 2 has finished completely etc.).

Basically, the // and /* ... */ comments are recognized in phase three, that is performed after the trailing \ handling (i.e. phase two), meaning that it is agnostic to them. In other words, it treats them just like an ordinary source text with no special meaning.

  1. Each instance of a backslash character (\) immediately followed by a new-line character is deleted, splicing physical source lines to form logical source lines. Only the last backslash on any physical source line shall be eligible for being part of such a splice.

  2. The source file is decomposed into preprocessing tokens7) and sequences of white-space characters (including comments). A source file shall not end in a partial preprocessing token or in a partial comment.Each comment is replaced by one space character. New-line characters are retained. Whether each nonempty sequence of white-space characters other than new-line is retained or replaced by one space character is implementation-defined.

Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • I modifie the question text to clarify that I already know that this is the case (check the references I gave in the question), what I don't understand is why this choice was made. – Ayberk Özgür Jun 08 '16 at 07:19