Discussion:
A macro question
(too old to reply)
Ray
2009-11-29 09:11:01 UTC
Permalink
Hello,

In the following code, the statement x = --1; causes an lvalue error as
expected, but the statement x = -N; does not. I was actually surprised that
x = -N; did not cause an error since I had always assumed that macro
substitutions occurred in what amounted to "copy and paste" operations rather
than "pre-evaluations". In this case, however, the preprocessor seems to be
first evaluating -1, then decrementing the resultant value and assigning it
to x. Thus, the compiler never sees -N as --1. But of course if the
compiler is instructed to produce a preprocessed (.i) file, x = -N; will be
converted to x = --1; in that file.

So, my question is this: Is the preprocessor required to produce a
pre-computed value for each macro whenever possible before that macro is
actually used, or is it within its rights to simply do a copy and paste until
all substitutions have been made, thus producing --1 in this case, which
would then cause a compiler error? Of course, if the macro were written
correctly (with parentheses) it wouldn't matter.

Thanks,
Ray

#define N -1

void fcn2()
{
int x;

x = -N;
x = --1;
}
Bo Persson
2009-11-29 12:48:37 UTC
Permalink
Post by Ray
Hello,
In the following code, the statement x = --1; causes an lvalue
error as expected, but the statement x = -N; does not. I was
actually surprised that x = -N; did not cause an error since I had
always assumed that macro substitutions occurred in what amounted
to "copy and paste" operations rather than "pre-evaluations". In
this case, however, the preprocessor seems to be first evaluating
-1, then decrementing the resultant value and assigning it to x.
Thus, the compiler never sees -N as --1. But of course if the
compiler is instructed to produce a preprocessed (.i) file, x = -N;
will be converted to x = --1; in that file.
So, my question is this: Is the preprocessor required to produce a
pre-computed value for each macro whenever possible before that
macro is actually used, or is it within its rights to simply do a
copy and paste until all substitutions have been made, thus
producing --1 in this case, which would then cause a compiler
error? Of course, if the macro were written correctly (with
parentheses) it wouldn't matter.
Thanks,
Ray
#define N -1
void fcn2()
{
int x;
x = -N;
x = --1;
}
You are in the very dark corners of the language (C language, that
is).

The preprocessor has to tokenize the source before using it. It is not
a straight text replacement!

So, your code

x = -N;

ends up being

x = - -1;

setting x to +1.

Totally different! :-)


Bo Persson
Igor Tandetnik
2009-11-29 14:45:31 UTC
Permalink
Post by Ray
In the following code, the statement x = --1; causes an lvalue error as
expected, but the statement x = -N; does not.
This question has been beaten to death here:

http://groups.google.com/group/microsoft.public.vc.language/browse_frm/thread/a1287c0abf1f419

(your example, or rather one substantially similar, first appears in message #5 in this thread).
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
Ray
2009-11-29 19:24:01 UTC
Permalink
Post by Ray
Hello,
In the following code, the statement x = --1; causes an lvalue error as
expected, but the statement x = -N; does not. I was actually surprised that
x = -N; did not cause an error since I had always assumed that macro
substitutions occurred in what amounted to "copy and paste" operations rather
than "pre-evaluations". In this case, however, the preprocessor seems to be
first evaluating -1, then decrementing the resultant value and assigning it
to x. Thus, the compiler never sees -N as --1. But of course if the
compiler is instructed to produce a preprocessed (.i) file, x = -N; will be
converted to x = --1; in that file.
So, my question is this: Is the preprocessor required to produce a
pre-computed value for each macro whenever possible before that macro is
actually used, or is it within its rights to simply do a copy and paste until
all substitutions have been made, thus producing --1 in this case, which
would then cause a compiler error? Of course, if the macro were written
correctly (with parentheses) it wouldn't matter.
Thanks,
Ray
#define N -1
void fcn2()
{
int x;
x = -N;
x = --1;
}
I guess I'm better at saying "duh" than understanding macros. After reading
the link provided by Igor I realize what is happening, that is, the macros
are tokenized before replacement, as stated by Bo. I was under the mistaken
impression that it was a simple "copy and paste" operation. Thanks for the
help.

Ray
Cezary H. Noweta
2009-12-02 13:34:33 UTC
Permalink
Hello,
Post by Ray
I guess I'm better at saying "duh" than understanding macros.
VC preprocessor is quite buggy. Playing with complex macros requires a
perfect knowledge of C/C++ macros. Many of correct constructs will fail
under MSVC (see a bug described by Igor in 84th post of mentioned
thread). As opposite, many of incorrect constructs will pass under MSVC
(see workaround for the above-mentioned bug). Portable solution requires
some additional intermediate macro.
Post by Ray
After reading
the link provided by Igor I realize what is happening, that is, the macros
are tokenized before replacement, as stated by Bo. I was under the mistaken
impression that it was a simple "copy and paste" operation.
Unfortunately ;) you are under the right impression. According to the
standard macros should play with tokens - not with text. However, under
some circumstances, MSVC's preprocessor acts as Macroassembler. ,,Modus
operandi'' of MSVC's preprocessor is a long story - (at least) as long
as ,,#define and (brackets)'' thread. For example, try to put ,,#define
N2 -N'', and thereafter ,,int i = N2;'' in your example - according to
the standard it should pass, but it will not. Thus your impression is
right in same cases. Results can be funny and unexpected:

#define A() 1

#define B .A()9

#define C A()00

If you are not (perfectly) familiar with macros then use them as
constants' names (,,#define F_MYFLAG 0x10'') and as a shortcut for
commonly used expressions (at the best enclosed in ,,()'' - ,,#define
OUTDW(v) (printf("%u", (v)))'' only.

At the end, but most important: do _not_ use MSVC if you want to
experiment with macros for educational purposes. Try some other compiler
(for example Comeau is good enough). When you know how a compiler should
process macros, then you are ready to experiment with MSVC and to
discover what the compiler really do.

-- best regards

Cezary Noweta

Continue reading on narkive:
Loading...