views:

499

answers:

4

I was looking at the program at http://www0.us.ioccc.org/1988/westley.c, mentioned in another SO answer - it's supposed to print the value of pi, about 3.142, but when I compile it and run it I get 0.250. It looks like when the GCC preprocessor (both 4.1.2 and 3.4.6 tested) runs on the code, it converts

#define _ -F<00||--F-OO--;
_-_-_

to

-F<00||--F-OO--;- -F<00||--F-OO--;- -F<00||--F-OO--;

but I think, for the program to work, it should be

-F<00||--F-OO--;--F<00||--F-OO--;--F<00||--F-OO--;

i.e. GCC is inserting an extra space before the "macro" expansion. Is that the way #define is supposed to work? (Has that changed since 1988?)

EDIT: Also, any information about how to prevent those spaces from showing up would be appreciated.

A: 

Yes, gcc is inserting extra spaces (verify by checking the stdout output of gcc -E westley.c(. As far as I know this behavior is compliant to the standard.

pts
It's pretty clear that the OP knows that it IS. He wants to know if it's SUPPOSED to.
Chris Lutz
Chris is right. I checked the output of gcc -E and found that extra spaces had been inserted, thus prompting me to ask this question.
David Zaslavsky
+6  A: 

The preprocessor operates on tokens, not strictly text. So technically it doesn't "put a space" in between, but unless you explicitly tell it to paste two tokens together with the ## operator, it won't do it. In this case the two -'s across macro lines are counted as two different tokens - both meaning unary minus, not decrement.

see also: http://en.wikipedia.org/wiki/C_preprocessor#Token_concatenation

Greg Rogers
I think the '-'s are unary minus, not binary subtract, in this context.
Chris Lutz
I'm accepting this answer as the clearest explanation of what's going on ;-) I edited it according to Chris's comment (since I'm accepting it, I figure accuracy is kind of important).
David Zaslavsky
+3  A: 

From the C99 standard:

A preprocessing directive of the form

# define identifier replacement-list new-line

defines an object-like macro that causes each subsequent instance of the macro name to be replaced by the replacement list of preprocessing tokens that constitute the remainder of the directive.

So macros work on tokens and the whitepace is to be expected.

And you can get the output you want using the token pasting operator, ##, but you need to use some further macro ugliness to do it:

#define PASTE2( x, y) x##y
#define PASTE( x, y) PASTE2(x, y)

#define _ -F<00||--F-OO--;


PASTE(PASTE(PASTE(PASTE(_,-),_),-),_)

So I'm not sure that this is a real answer for you.

You can use a less ugly set of macros to get the expresions you want - there will still be some spaces, but the spaces won't interfere with creating the '--' operators:

_ PASTE(-,_) PASTE(-,_)

I still doubt that's what you want, though.

Michael Burr
+7  A: 

Only much older preprocessors didn't insert that extra space -- note that original entry was submitted over 20 years ago in 1988, before the 1989 version of the C standard was standardized. You can pass the -traditional-cpp flag to the GCC preprocessor, which causes it to imitate the behavior of old-fashioned C preprocessors, as opposed to ISO C preprocessors.

Adam Rosenfield
Good info. And this reminds me that they would sometimes do token pasting using something like `#define PASTE(x,y) x/**/y` where the comment would disappear without a trace.
Michael Burr
That idiom for paste is what motivated the standards committee to create a formal operator. Once they specified that a comment was to be replaced by a single white space, it broke the idiom.
RBerteig