Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

During C macro expansion, is there a special case for macros that would expand to "/*"?

Here's a relevant example. It's obviously not valid C, but I'm just dealing with the preprocessor here, so the code doesn't actually have to compile.

#define IDENTITY(x) x
#define PREPEND_ASTERISK(x) *x
#define PREPEND_SLASH(x) /x

IDENTITY(literal)
PREPEND_ASTERISK(literal)
PREPEND_SLASH(literal)
IDENTITY(*pointer)
PREPEND_ASTERISK(*pointer)
PREPEND_SLASH(*pointer)

Running gcc's preprocessor on it:

gcc -std=c99 -E macrotest.c

This yields:

(...)

literal
*literal
/literal
*pointer
**pointer
/ *pointer

Please note the extra space in the last line.

This looks like a feature to prevent macros from expanding to "/*" to me, which I'm sure is well-intentioned. But at a glance, I couldn't find anything pertaining to this behaviour in the C99 standard. Then again, I'm inexperienced at C. Can someone shed some light on this? Where is this specified? I would guess that a compiler adhering to C99 should not just insert extra spaces during macro expansion just because it would probably prevent programming mistakes.

like image 378
curious_programmer Avatar asked Nov 12 '10 13:11

curious_programmer


People also ask

How are macros expanded in C?

The LENGTH and BREADTH are called the macro templates. The values 10 and 20 are called macro expansions. When the program run and if the C preprocessor sees an instance of a macro within the program code, it will do the macro expansion. It replaces the macro template with the value of macro expansion.

What does macro table size expand to?

(If it does not, you may get error messages from the C compiler when you use the macro.) TABLESIZE is expanded first to produce BUFSIZE, then that macro is expanded to produce the final result, 1024.

What does the '#' symbol do in macro expansion?

The number-sign or "stringizing" operator (#) converts macro parameters to string literals without expanding the parameter definition. It's used only with macros that take arguments.


2 Answers

The source code is already tokenized before being processed by CPP.

So what you have is a / and a * token that will not be combined implicitly to a /* "token" ( since /* is not really a preprocessor token I put it in "").

If you use -E to output preprocessed source CPP needs to insert a space in order to avoid /* being read by a subsequent compiler pass.

The same feature prevents from two e.g. + signs from different macros being combined into a ++ token on output.

The only way to really paste two preprocessor tokens together is with the ## operator:

#define P(x,y) x##y

...

P(foo,bar)   

results in the token foobar

P(+,+)

results in the token ++, but

P(/,*)       

is not valid since /* is not a valid preprocessor token.

like image 155
Peer Stritzinger Avatar answered Sep 21 '22 17:09

Peer Stritzinger


The behavior of the pre-processor is standardized. In the summary at http://en.wikipedia.org/wiki/C_preprocessor , the results you are observing are the effect of:

"3: Tokenization - The preprocessor breaks the result into preprocessing tokens and whitespace. It replaces comments with whitespace".

This takes place before:

"4: Macro Expansion and Directive Handling".

like image 35
Pascal Cuoq Avatar answered Sep 19 '22 17:09

Pascal Cuoq