Re: #define and (brackets)



"Igor Tandetnik" <itandetnik@xxxxxxxx> wrote in message
news:OD73zvqTJHA.4744@xxxxxxxxxxxxxxxxxxxxxxx
"Alan Carre" <alan@xxxxxxxxxxxxxxxxx> wrote in message
news:O2UQLypTJHA.1332@xxxxxxxxxxxxxxxxxxxx
Correction. On it's own it works, but in a macro it doesn't:

#define SHRX -10
#define SHRY -20
#define SHRINK(rect) rect.DeflateRect(-6-SHRX,6-SHRY)

You get a compile error.

This looks like a bug in MSVC compiler. This program:

Boy, go away for a day or 2 and all hell breaks loose!

----

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: #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: question on const
    ... >It seems to be compiler dependent and even changes with optimisations. ... >value of num is 200 ... Now, as it happens, gcc is not able or willing to place this variable ... in read-only memory (because gcc assumes there is a conventional ...
    (comp.lang.c)
  • 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)

Loading