Calling multiple functions in a mac

mcdaniel at uicsrd.csrd.uiuc.edu mcdaniel at uicsrd.csrd.uiuc.edu
Fri Nov 4 16:26:00 AEST 1988


Written  1:43 pm  Nov  1, 1988 by knudsen at ihlpl.ATT.COM in comp.lang.c:
> In article <353 at marob.MASA.COM>, daveh at marob.MASA.COM (Dave Hammond) writes:
>> #define FOO()	do { foo1(); foo2(); foo3() foo4(); } while(0)
> Why use the do and while?  C has blocks, you can say just plain
>	{foo1(); ... foo4();}

Try compiling this code:
	#include <stdio.h>
    
	#define FOO() { printf("Hello, "); printf("world!\n"); }
    
	main() 
	{
	    if (1)
		FOO();          /* line 8 */
	    else		/* line 9 */
		exit(1);
	    exit(0);
	}

If your compiler is like mine (PCC, on a VAX, under BSD 4.3), it will
reply:
	"t.c", line 9: syntax error

According to K&R, first edition, the syntax of the "if" statement is
	if ( <expression> ) <statement> else <statement>
and <statement> is
	;
(the null statement) or
	{ <declaration-list-opt> <statement-list-opt> }
(or "for ...", "while ...", "<expression> ;", et cetera)  Thus
	if (1) { } ; else ;
is illegal. "{ }" is one statement, and ";" is another (a null
statement), and you can have only one statement between an "if" and
its "else".

One choice is to remove the ";" on line 8.  Then it looks like a
function call without a ";" after it, which looks weird.

Thus, the usual way to define such a FOO() is
	#define FOO()	do { foo1(); foo2(); foo3() foo4(); } while(0)
or
	#define FOO()	if (1) { foo1(); foo2(); foo3() foo4(); } else
NOTE the "else" in the second case.  If it were omitted,
	if (x) FOO(); else BAR();
would cause a syntax error, and if the semicolon were removed,
	if (x) FOO()  else BAR();
the "else" pairs with the "if" in FOO, NOT the "if (x)".

The problem with THESE solutions is that "lint -h" under BSD 4.3 starts
spitting out messages like
	t.c(7): warning: constant in conditional context
	t.c(8): warning: constant argument to NOT
You DO lint all your code, don't you? 8-(  To remove these messages, I
use a common ".h" file with
	#ifdef lint
	static int true = 1;
	static int false = 0;
	#else
	#define true 1
	#define false 0
	#endif
and use "do ... while (false)" and "if (true) ... else".  All for the
lack of an "inline" keyword in standard C.  *sigh*

A better definition is
>> #define FOO()        foo1(), foo2(), foo3(), foo4()
because it can be used in expressions.  However, you should use
parentheses around macro text!  Consider
	bar(FOO())
You expect bar() to be called with one argument, the value of foo4(),
but instead bar() is called with 4 arguments.  (Lint catches most
errors of this kind, which means most programmers will never notice
this error until it causes the program to core dump.  8-( )

In general, when you write macros that evaluate to expressions, you
should parenthesize the result, as above.

By the way, you should also parenthesize all uses of macro arguments.
Consider
	#define two_it(x) (2*x)
The whole thing is parenthesized, which is as suggested above.
However, if it is called as "two_it(x+y)", this call becomes
"(2*x+y)", which is probably NOT what you expected.
	#define two_it(x) (2*(x))
works better.

-- 
Tim, the Bizarre and Oddly-Dressed Enchanter
Center for Supercomputing Research and Development
at the University of Illinoid at Urbana-Champaign

Internet, BITNET:  mcdaniel at uicsrd.csrd.uiuc.edu
UUCP:    {uunet,convex,pur-ee}!uiucuxc!uicsrd!mcdaniel
ARPANET: mcdaniel%uicsrd at uxc.cso.uiuc.edu
CSNET:   mcdaniel%uicsrd at uiuc.csnet
DECnet?: GARCON::"mcdaniel at uicsrd.csrd.uiuc.edu"



More information about the Comp.lang.c mailing list