Re: #define and (brackets)



That's what I have warned against. That separate preprocessing and
compilation is NOT the same as one-shot preprocessing and compilation.

Per ANSI C standard, there is NO re-pre-process (NO re-tokenization).

The compiler doesn't second-guess. It just follows the standard. May not
always be doing that, but in these cases it does.

By the way, I don't see what's the point in your stringizing example.
Operator # replaces the whole proprocessing token sequence for an argument
with a string.

"Alan Carre" <alan@xxxxxxxxxxxxxxxxx> wrote in message
news:eAOBdgWUJHA.5244@xxxxxxxxxxxxxxxxxxxxxxx
----

I think you guys a probably talking way over my head about multiple pass
compilation and re-tokenization expansion blah blah blah... But, for my
own sake at least, let's just look at a simple, very well-known fact about
the pre-processor for one minue:

#define STRIZE(x) #x // converts the argument into a
string.
#define _STRIZE_(x) STRIZE(x) // converts the pre-preocessed argument to
a string.

#define NUM -10

int main(int argc, ...)
{
puts(STRIZE(NUM));
puts(_STRIZE_(NUM));
puts(_STRIZE_(-NUM));
return 0;
}

Output:
--------
NUM
-10
--10

What can we learn from this?

This is how I see it:
=============

Case 1: STRIZE is passed a value x as NUM. The preprocessor allocates a
textual representation for x (*x* not NUM) as the value "NUM" (no quotes).
I just mean internally it's a string containing the word NUM. The macro
says #x which means to put quotations around this value so out pops "NUM"
in the source file. Case 1 explained.

Case 2: _STRIZE_ is passed x as NUM again. The preprocessor again creates
a textual representation for x, substituting it again as "NUM" (no
quotes!). Next, it must evaluate the macro but this time instead of #NUM
it is given STRIZE(NUM). At this point the preprocessor must decide what
to pass as x for STRIZE. So it is forced to try to expand NUM; to see if
it already exists as a macro (which it does) and that macro evaluates
to -10 (again textually, and internally). So the preprocessor then sets x
to "-10" (no quotes) passes that to STRIZE and finally evaluates #-10
which is "-10" in the source file (BTW. There are NO spaces before the
minus sign, you can double check if you don't believe me).

Case 3: In this case the preprocessor is passed -NUM into _STRIZE_ so x
has the textual representation -NUM. Again, it must re-evaluate this to
see if NUM is already a macro (and boy, if it didn't do that, and
treated -NUM as a *single token*, then NO macros would work at all!). So
the minus sign is not part of the token, only NUM is evaluated which
happens to be stored off as -10 [without any meaning! it's just what NUM
is when dereferenced from some string table]. Hence the expression -NUM
evaluates to --10 which is then passed into STRIZE for x and it winds up
as "--10" in the source file as expected (NO SPACES again).

============

So now then, the question is (or should be) "why does this work"?

int main(int argc,...)
{
printf("%d", -NUM);
}

Well I passed this through cl /E (preprocess to stdout) and got this as
the result:

int main(int argc, ...)
{
...lots of space...

printf("%d", --10);
return 0;

...lots of space...
}

Again, no spaces after the first minus sign, which should clearly have
generated a compiler error. CLEARLY. The above is cut and pasted from my
CMD box: It is byte-for-byte what is handed to the compiler from the
preprocessor. So it appears that there is a bug in the compiler in that it
must have re-interpreted the preprocessed file!

However it looks to me as though it is only smart enough to re-pre-process
1 level deep where, in this case, it can "see" that it would be better to
throw in a space there (at compilation time) because that's probably what
the programmer intended. Thanks cl.exe I wanted an error!

So there's your bug. The compiler shouldn't be in the business of
second-guessing the programmer's intentions with macros.

- Alan Carre





.



Relevant Pages

  • Re: How to define a const and initialize it?
    ... > do the same work as const int MYCONST will do.... ... But the thing is that macro substitution takes ... C++ compiler isn't even aware of its existence. ... This Item might better be called "prefer the compiler to the preprocessor," because #define is often ...
    (alt.comp.lang.learn.c-cpp)
  • Re: String comparison in preprocessor commands
    ... that won't work: The preprocessor can generate ... string literals, but it can't actually work with strings. ... and rely on the compiler to eliminate dead code: ... > position to change the macro definition. ...
    (comp.lang.c)
  • Re: #define and (brackets)
    ... This looks like a bug in MSVC compiler. ... STRIZE is passed a value x as NUM. ... The preprocessor again creates a ... it must evaluate the macro but this time instead of #NUM it is given ...
    (microsoft.public.vc.language)
  • Re: #ifdef inside macro expansion
    ... The preprocessor is what you are looking at - not the compiler. ... a macro with, so this is expected bhavior - not a bug. ...
    (microsoft.public.vc.language)
  • Re: Preprocessing directive in the middle of macro arguments
    ... this compiler seems confused by any preprocessing ... conditionaly select one of several arguments passed to a macro. ... All preprocessor directives are processed before any macro expansion ...
    (comp.lang.c)