macros and side effects

C

copx

Is it true that C macros are unsafe when combined with side effects even if
they are "clean" e.g. could

foo_macro(++c);

execute "++c" multiple times even if foo_macro is "clean"? I have always
thought that "clean" macros (i.e. macros where all parameters are
surrounded by parentheses in the definition) do not have this problem...

I am wondering because I have just looked up putc() in a reference, and it
says that it is unsafe if the "passed" value has a side effect, and I assume
standard macros are "clean"...
 
C

Charlton Wilbur

c> Is it true that C macros are unsafe when combined with side
c> effects even if they are "clean" e.g. could

c> foo_macro(++c);

#define foo_macro(x) (x)*(x)

Whoops.

Charlton
 
G

Guest

copx said:
Is it true that C macros are unsafe when combined with side effects even if
they are "clean" e.g. could

foo_macro(++c);

execute "++c" multiple times even if foo_macro is "clean"? I have always
thought that "clean" macros (i.e. macros where all parameters are
surrounded by parentheses in the definition) do not have this problem...

I am wondering because I have just looked up putc() in a reference, and it
says that it is unsafe if the "passed" value has a side effect, and I assume
standard macros are "clean"...

Your reference is correct, and "clean" macros can evaluate their
arguments multiple times. As a simple example, if you have

#define foo_macro(x) ((x) * (x))

then foo_macro's arguments are fully parenthesised, but foo_macro(++c)
will still expand to ((++c) * (++c)).

For most standard library functions, it is required that if they are
also implemented as a macro, that that macro evaluates each argument
exactly once. putc is an exception.
 
R

Richard Heathfield

copx said:
Is it true that C macros are unsafe

Not if written correctly and used correctly.
when combined with side effects even if they are "clean" e.g. could

foo_macro(++c);

execute "++c" multiple times even if foo_macro is "clean"?

That is not a widely-used term for describing macros. (Translation: it's
the first time I have ever seen it.)
I have
always
thought that "clean" macros (i.e. macros where all parameters are
surrounded by parentheses in the definition) do not have this
problem...

You thought wrong.
I am wondering because I have just looked up putc() in a reference,
and it says that it is unsafe if the "passed" value has a side effect,

Your reference says wrong. The putc function, if implemented as a macro,
may evaluate the stream more than once, but *not* the character. And
you're hardly likely to call it as putc('\n', fp++), I trust?
and I assume standard macros are "clean"...

Why?
 
G

Guest

Richard said:
copx said:

Your reference says wrong. The putc function, if implemented as a macro,
may evaluate the stream more than once, but *not* the character.

That's a useful clarification, but it doesn't mean the reference is
wrong.
 
E

Eric Sosman

Richard Heathfield wrote On 05/04/07 12:34,:
copx said:
[...] "clean" macros (i.e. macros where all parameters are
surrounded by parentheses in the definition) [...]

and I assume standard macros are "clean"...


Why?

Perhaps because of the Standard? 6.10.8 lists the
values of the predefined macros, and all are "clean."
7.1.2p5 requires "cleanliness" of all object-like macros
defined in the standard headers, and 7.1.4p2 does the same
for function-like macros that implement standard library
functions. What remains are the dribs and drabs like
va_start() and setjmp(); do you find them "unclean" (in
the O.P.'s sense, that is)?
 
D

Dave Vandervies

copx said:


Not if written correctly and used correctly.

It's worth noting, though, that they're one of the easier parts of the
language to get wrong unintentionally, and it's sometimes easy to convert
correct use into incorrect use without realizing it, even if you do know
what you're doing.

If you compare programming in C to running with scissors, a lot of code
that uses macros ends up being at the pointy end of the scissors.


dave
(runs around the pool with scissors)
 
B

Bart van Ingen Schenau

copx said:
Is it true that C macros are unsafe when combined with side effects
even if they are "clean" e.g. could

foo_macro(++c);

execute "++c" multiple times even if foo_macro is "clean"?
Yes.

I have
always
thought that "clean" macros (i.e. macros where all parameters are
surrounded by parentheses in the definition) do not have this
problem...

Because macros are essentially a form of text substitution, the
parentheses in a macro definition can not influence how often an
argument gets evaluated.

The parentheses around macro arguments are needed to ensure that the
parser always interprets the complete argument as a single expression.
For example, take these two macros:

#define HALVE(x) x/2
#define DIVIDE_BY_TWO(x) (x)/2

When you use them like this:

y = HALVE(3+1);
z = DIVIDE_BY_TWO(3+1);

the preprocessor will replace the macros, yielding:

y = 3+1/2;
z = (3+1)/2;

Do you see the difference between the two statements?
I am wondering because I have just looked up putc() in a reference,
and it says that it is unsafe if the "passed" value has a side effect,
and I assume standard macros are "clean"...

Bart v Ingen Schenau
 
F

Fred Kleinschmidt

Harald van D?k said:
Your reference is correct, and "clean" macros can evaluate their
arguments multiple times. As a simple example, if you have

#define foo_macro(x) ((x) * (x))

then foo_macro's arguments are fully parenthesised, but foo_macro(++c)
will still expand to ((++c) * (++c)).

For most standard library functions, it is required that if they are
also implemented as a macro, that that macro evaluates each argument
exactly once. putc is an exception.

Not "exactly once", but "at most once". It is quite legitimate for
some argument to not be evaluated at all.
 
C

copx

Bart van Ingen Schenau said:
Because macros are essentially a form of text substitution, the
parentheses in a macro definition can not influence how often an
argument gets evaluated.

The parentheses around macro arguments are needed to ensure that the
parser always interprets the complete argument as a single expression.
For example, take these two macros:

#define HALVE(x) x/2
#define DIVIDE_BY_TWO(x) (x)/2

When you use them like this:

y = HALVE(3+1);
z = DIVIDE_BY_TWO(3+1);

the preprocessor will replace the macros, yielding:

y = 3+1/2;
z = (3+1)/2;

Do you see the difference between the two statements?
[snip]

Yes, I remember that much of kindergarten math ;)

Thanks everyone.
 
R

Richard Heathfield

Eric Sosman said:
Richard Heathfield wrote On 05/04/07 12:34,:
copx said:
[...] "clean" macros (i.e. macros where all parameters are
surrounded by parentheses in the definition) [...]

and I assume standard macros are "clean"...


Why?

Perhaps because of the Standard? 6.10.8 lists the
values of the predefined macros, and all are "clean."

Those are macros such as __FILE__, and they don't take parameters, so I
don't see why they're relevant.
7.1.2p5 requires "cleanliness" of all object-like macros
defined in the standard headers,
Sure.

and 7.1.4p2 does the same
for function-like macros that implement standard library
functions.

7.1.4p2 (of C99 - there is no such paragraph in C89) says:

2 Provided that a library function can be declared without reference to
any type defined in a header, it is also permissible to declare the
function and use it without including its associated header.

I don't see how this says anything about parenthetical protection for a
function-like macro's arguments.
What remains are the dribs and drabs like
va_start() and setjmp(); do you find them "unclean" (in
the O.P.'s sense, that is)?

As far as I am aware, that depends on the implementation.
 
E

Eric Sosman

Fred Kleinschmidt wrote On 05/04/07 14:20,:
Not "exactly once", but "at most once". It is quite legitimate for
some argument to not be evaluated at all.

Not "at most once," but "exactly once," and it is
ILlegitimate to omit evaluating an argument. 7.1.4p1:

[...] Any invocation of a library function that is
implemented as a macro shall expand to code that
evaluates each of its arguments exactly once, fully
protected by parentheses where necessary, [...]
 
R

Richard Heathfield

Harald van D?k said:
That's a useful clarification, but it doesn't mean the reference is
wrong.

It's wrong because of 4.1.6 (C89) and 7.1.4(1) (C99):

"Any invocation of a library function that is implemented as
a macro shall expand to code that evaluates each of its arguments
exactly once, fully protected by parentheses where necessary, so it is
generally safe to use arbitrary expressions as arguments."

....and that means that there is an apparent contradiction between the
above text and the description of putc in 4.9.7.8 (C89) and 7.19.7.8
(C99). Has this been the subject of any DRs?
 
R

Richard Heathfield

Dave Vandervies said:

If you compare programming in C to running with scissors, a lot of
code that uses macros ends up being at the pointy end of the scissors.

Aye - it's snipped out, and discarded. :)
 
E

Eric Sosman

Richard Heathfield wrote On 05/04/07 14:55,:
Eric Sosman said:

Richard Heathfield wrote On 05/04/07 12:34,:
copx said:


[...] "clean" macros (i.e. macros where all parameters are
surrounded by parentheses in the definition) [...]

and I assume standard macros are "clean"...


Why?

Perhaps because of the Standard?
[...]
and 7.1.4p2 does the same
for function-like macros that implement standard library
functions.


7.1.4p2 (of C99 - there is no such paragraph in C89) says:

2 Provided that a library function can be declared without reference to
any type defined in a header, it is also permissible to declare the
function and use it without including its associated header.

I don't see how this says anything about parenthetical protection for a
function-like macro's arguments.

My error: should have been p1, not p2.

"[...] Any invocation of a library function that
is ipmlemented as a macro shall expand to code
that evaluates each of its arguments exactly once,
fully protected by parentheses where necessary [...]"
As far as I am aware, that depends on the implementation.

Perhaps you're right. I shall henceforth avoid
code like

va_list array[10], *ap = array;
va_start (ap + 5, parmN);

.... even though it'll cramp my style.
 
K

Keith Thompson

Richard Heathfield said:
Harald van D?k said:


It's wrong because of 4.1.6 (C89) and 7.1.4(1) (C99):

"Any invocation of a library function that is implemented as
a macro shall expand to code that evaluates each of its arguments
exactly once, fully protected by parentheses where necessary, so it is
generally safe to use arbitrary expressions as arguments."

...and that means that there is an apparent contradiction between the
above text and the description of putc in 4.9.7.8 (C89) and 7.19.7.8
(C99). Has this been the subject of any DRs?

There's no need for a DR. Go back to the beginning of paragraph C99
7.1.4p1:

Each of the following statements applies unless explicitly stated
otherwise in the detailed descriptions that follow:
[...]

The description of putc() explicitly states otherwise.
 
L

lawrence.jones

Richard Heathfield said:
...and that means that there is an apparent contradiction between the
above text and the description of putc in 4.9.7.8 (C89) and 7.19.7.8
(C99). Has this been the subject of any DRs?

No, because the very first sentence of 4.1.6/7.1.4 resolves it:

Each of the following statements applies unless explicitly
stated otherwise in the detailed descriptions that follow:

So the explicit license in the description of putc takes precedence.

-Larry Jones

The hardest part for us avant-garde post-modern artists is
deciding whether or not to embrace commercialism. -- Calvin
 
R

Richard Heathfield

Keith Thompson said:

There's no need for a DR. Go back to the beginning of paragraph C99
7.1.4p1:

Each of the following statements applies unless explicitly stated
otherwise in the detailed descriptions that follow:
[...]

The description of putc() explicitly states otherwise.

No fair! Expecting me to /read/ the thing, as opposed to merely
searching it...
 
P

pete

Richard said:
Harald van D?k said:


It's wrong because of 4.1.6 (C89) and 7.1.4(1) (C99):

"Any invocation of a library function that is implemented as
a macro shall expand to code that evaluates each of its arguments
exactly once, fully protected by parentheses where necessary, so it is
generally safe to use arbitrary expressions as arguments."

...and that means that there is an apparent contradiction between the
above text and the description of putc in 4.9.7.8 (C89) and 7.19.7.8
(C99). Has this been the subject of any DRs?

There's two exceptions.
putc is one, getc is the other.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,955
Messages
2,570,117
Members
46,705
Latest member
v_darius

Latest Threads

Top