[comp.lang.c] Using Macros

yoke@astro.pc.ab.com (Michael Yoke) (08/07/90)

Could some of you give me your opinion on the best way to handle multiple 
statement macros.  For example, let's say that I have a macro that looks
like the following:

         #define A_MACRO       (stmt1)

and the code that uses the macro looks like this:

        if (expr)
           A_MACRO;

Now let's say that the macro has to be modified such that it requires
more than one statement.  If I define the macro like this,

      #define A_MACRO (stmt1; stmt2;)

then all the code using the macro must be changed to
  
      if (expr) {
         A_MACRO;
      }

But, if I define the macro like this

      #define A_MACRO { stmt1; stmt2; }

then the semi-colon at the end of the macro reference screws things up.

I guess what I'm really looking for is a good set of guidelines for using 
macros.

                            Thanks in advance,

                            Mike

farrell@onedge.enet.dec.com (Bernard Farrell) (08/07/90)

In article <362.26be9dcc@astro.pc.ab.com>, yoke@astro.pc.ab.com (Michael Yoke) writes...

(Some earlier statments removed)

>But, if I define the macro like this
> 
>      #define A_MACRO { stmt1; stmt2; }
> 
>then the semi-colon at the end of the macro reference screws things up.
> 
  When used in

	for (something)
	   A_MACRO;

Michael, the macro expansion would give you:

	for (something)
	{
		stmt1;
		stmt2;
	};

[Indentation is mine for clarity].  The presence of an empty statement after
the closing brace should not cause any problems, though I seem to recall
certain C compilers don't like it being placed here.


Bernard Farrell                | 
  farrell@onedge.enet.dec.com  | Strange but true:
 often on the move so try      |   These thoughts are my own invention,
 home: (617) 332-6203          |   I wish I could blame someone else for
                               |   them !!

volpe@underdog.crd.ge.com (Christopher R Volpe) (08/08/90)

In article <14339@shlump.nac.dec.com>, farrell@onedge.enet.dec.com
(Bernard Farrell) writes:
|>
|>In article <362.26be9dcc@astro.pc.ab.com>, yoke@astro.pc.ab.com
(Michael Yoke) writes...
|>>But, if I define the macro like this
|>> 
|>>      #define A_MACRO { stmt1; stmt2; }
|>> 
|>>then the semi-colon at the end of the macro reference screws things up.
|>> 
|>The presence of an empty statement after
|>the closing brace should not cause any problems, though I seem to recall
|>certain C compilers don't like it being placed here.

Can someone with a copy of the Standard tell us if a semicolon is 
allowed? K&R2 is vague on the issue ("there is no semicolon after the
closing brace". Does this mean "no semicolon necessary" or 
"no semicolon allowed"?). 

Anyway, if the compiler is coughing on it, try the following:

         #define A_MACRO {stmt1;stmt2;} 0  /* yes, trailing zero */

Expanding "A_MACRO;" yields the dummy statement "0;" which is
basically a value that goes unused, much like ignoring the return value
of a function, except that no function gets called and no code (should)
be generated. (Sun C and GNU C accept "0;" as a statement and generate
no code.) 
                                  

manning@gap.caltech.edu (Evan Marshall Manning) (08/08/90)

farrell@onedge.enet.dec.com (Bernard Farrell) writes:

>In article <362.26be9dcc@astro.pc.ab.com>, yoke@astro.pc.ab.com (Michael Yoke) writes...

>(Some earlier statments removed)

>>But, if I define the macro like this
>> 
>>      #define A_MACRO { stmt1; stmt2; }
>> 
>>then the semi-colon at the end of the macro reference screws things up.
>> 
>  When used in

>	for (something)
>	   A_MACRO;

>Michael, the macro expansion would give you:

>	for (something)
>	{
>		stmt1;
>		stmt2;
>	};

>[Indentation is mine for clarity].  The presence of an empty statement after
>the closing brace should not cause any problems, though I seem to recall
>certain C compilers don't like it being placed here.

I believe the fun variant is:

	if (something)
	    A_MACRO;
	else
	    it_doesn_t_matter;

Try nesting the ifs for more fun!

Gimple Lint will catch this type of errors, as unusual indentation.

-- Evan

***************************************************************************
Your eyes are weary from staring at the CRT for so | Evan M. Manning
long.  You feel sleepy.  Notice how restful it is  |      is
to watch the cursor blink.  Close your eyes.  The  |manning@gap.cco.caltech.edu
opinions stated above are yours.  You cannot       | manning@mars.jpl.nasa.gov
imagine why you ever felt otherwise.               | gleeper@tybalt.caltech.edu

farrell@onedge.enet.dec.com (Bernard Farrell) (08/08/90)

In article <10836@crdgw1.crd.ge.com>, volpe@underdog.crd.ge.com (Christopher R Volpe) writes...

(in reference to a construct like)

	if (blah)
	{
	    stmt1;
	    stmt2;
	};
>           
>Can someone with a copy of the Standard tell us if a semicolon is 
>allowed? K&R2 is vague on the issue ("there is no semicolon after the
>closing brace". Does this mean "no semicolon necessary" or 
>"no semicolon allowed"?). 

The Standard simply comments on the Null statement in 3.6.3 as one that
"performs no operations".   There is no reference to Null statements in
the context of Block statements, 3.6.2., nor would I expect there
to be because the fact that the statement has a curly brace in front of
it really shouldn't modify it's meaning.


I believe K&R (n) was probably placating Pascal converts, and meant
no semicolon necessary.


Bernard Farrell                | 
  farrell@onedge.enet.dec.com  | Strange but true:
 often on the move so try      |   These thoughts are my own invention,
 home: (617) 332-6203          |   I wish I could blame someone else for
                               |   them !!

mlandau@bbn.com (Matthew Landau) (08/08/90)

Seems like this should be on the FAQ list, since it comes up every 
couple of months.  My preferred solution to the problem (which I 
picked up in comp.lang.c about 10 years ago :-) is:

   #define FOO(bar, baz)  do { func1(bar); func2(baz); } while (0)

Since there's no trailing semicolon after the while(0), this construct 
can be used anywhere a simple C statement can be used.  (Indeed, 
syntactically it is one statement.)  Moreover, any compiler worth its
salt should be able to optimize away the do ... while part, since the
code above is guaranteed to execute the stuff inside the braces exactly
once.

Of course lint and Saber will complain bitterly, but you can shut 
Saber up with judicious use of the SUPPRESS directive in the macro
definition.  Still haven't figured out how to get lint to quiet
down, but then again I don't use lint much now that I have Saber.
--
 Matt Landau			Oblivion gallops closer,
 mlandau@bbn.com		    favoring the spur, sparing the rein.

jgmicon@sandia.UUCP (Jeff G. Micono ) (08/08/90)

In article <10836@crdgw1.crd.ge.com>, volpe@underdog.crd.ge.com (Christopher R Volpe) writes:
> Anyway, if the compiler is coughing on it, try the following:
> 
>          #define A_MACRO {stmt1;stmt2;} 0  /* yes, trailing zero */
> 
> Expanding "A_MACRO;" yields the dummy statement "0;" which is ...ds

your solution fails with the following:

if (expr)
  A_MACRO;
else
  printf ("This will not work!\n");


What about

	# define A_MACRO	stmt1,stmt2
	/* no flames, yes I know it's gross, but it works! */


Jeff Micono of Ktech
Ktech Corporation, Albuquerque, NM  87801

"We provide ES&H solutions"

mcdaniel@adi.com (Tim McDaniel) (08/08/90)

yoke@astro.pc.ab.com (Michael Yoke) asks about multiple-statement
macros.

1. The comma operator, which only works for expressions:
	#define A_MACRO		(expr1, ..., exprn)

2. 
	#define A_MACRO		do { stmt1; ...; stmtn; } while (0)
   Any decent compiler should optimize the useless test out.
   Even if it doesn't, it shouldn't hurt speed much.
   Lint may require help to shut up about a "constant in a conditional
   context", or such.
--
"I'm not a nerd -- I'm 'socially challenged'."

Tim McDaniel
Internet: mcdaniel@adi.com             UUCP: {uunet,sharkey}!amara!mcdaniel

burley@world.std.com (James C Burley) (08/08/90)

In article <14404@diamond.BBN.COM> mlandau@bbn.com (Matthew Landau) writes:

   Seems like this should be on the FAQ list, since it comes up every 
   couple of months.  My preferred solution to the problem (which I 
   picked up in comp.lang.c about 10 years ago :-) is:

      #define FOO(bar, baz)  do { func1(bar); func2(baz); } while (0)

Hmmm, when I first saw the problem posted, I thought I knew the easy and
consistent answer, but all these other responses differ from mine.

Can anyone explain to me why

    #define FOO(bar,baz) (func1(bar), func2(baz))

wouldn't work in all the situations one could reasonably expect?  The macro
still expands to a single expression (as did the old version mentioned in the
original posting), right?  So a trailing semicolon causes it to be
interpreted as a statement, right?  The comma within the expansion serves
the same purpose of defining a sequence point as would the semicolon in other
solutions, right?  I have the horrible feeling I'm missing something, but I do
think I've done this before and it worked okay.

James Craig Burley, Software Craftsperson    burley@world.std.com

rh@smds.UUCP (Richard Harter) (08/08/90)

Sigh.  I will probably be one of many posting this, but this seems
to have already generated some confusion.  Shouldn't this be in
the "most frequently asked questions" posting?

If you have a block of statements defined in a macro which you
wish to use as though it were a function, there are several ways
to handle it.  Perhaps the clearest is:

#define A_MACRO(args) do {...body...} while(0)

This makes A_MACRO a statement.  This protection is needed when
you have A_MACRO in an if statement, e.g.

if (foo==bar) A_MACRO(moby);
else B_MACRO(gumby);

-- 
Richard Harter, Software Maintenance and Development Systems, Inc.
Net address: jjmhome!smds!rh Phone: 508-369-7398 
US Mail: SMDS Inc., PO Box 555, Concord MA 01742
This sentence no verb.  This sentence short.  This signature done.

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (08/08/90)

In article <14339@shlump.nac.dec.com>, farrell@onedge.enet.dec.com (Bernard Farrell) writes:
> In article <362.26be9dcc@astro.pc.ab.com>, yoke@astro.pc.ab.com (Michael Yoke) writes...
  [asks about defining macros that expand to more than one statement]

> 	};
> 
> The presence of an empty statement after
> the closing brace should not cause any problems,

I wasn't going to reply to this, but the Official Free Answer[*] is
to use the expansion
	do { /* your statements go here */ } while (0)
This will work in any context where a statement is allowed; it wants
a semi-colon after it just like a simple function call would.  For
example:
	#define swap(Type,x,y) do { \
	    Type *ZZQ1 = &(x); \
	    Type *ZZQ2 = &(y); \
	    Type  ZZQ3 = *ZZQ1; \
	    *ZZQ1 = *ZZQ2; *ZZQ2 = ZZQ3; \
	} while (0)

(Exercise for the reader:  why did I write 3 declarations instead of 1?)

[*] An Official Free Answer is something you find in an FSF manual,
    such as the manual for CCCP.
-- 
Taphonomy begins at death.

gg10@prism.gatech.EDU (GALLOWAY) (08/08/90)

In article <14404@diamond.BBN.COM>, mlandau@bbn.com (Matthew Landau) writes:
> ...
>    #define FOO(bar, baz)  do { func1(bar); func2(baz); } while (0)
> ...
> Of course lint and Saber will complain bitterly, but you can shut ...
> --
>  Matt Landau			Oblivion gallops closer,
>  mlandau@bbn.com		    favoring the spur, sparing the rein.

Why doesn't this work?

#define A_MACRO(bar, baz)  func1(bar), func2(baz)

I have been using syntax like this for awhile, is this wrong or unportable?

Also, what is Saber?

Greg Galloway
gg10@rism.gatech.edu

lerman@stpstn.UUCP (Ken Lerman) (08/08/90)

In article <151@smds.UUCP> rh@smds.UUCP (Richard Harter) writes:
->If you have a block of statements defined in a macro which you
->wish to use as though it were a function, there are several ways
->to handle it.  Perhaps the clearest is:
->
->#define A_MACRO(args) do {...body...} while(0)
->
->This makes A_MACRO a statement.  This protection is needed when
->you have A_MACRO in an if statement, e.g.
->
->if (foo==bar) A_MACRO(moby);
->else B_MACRO(gumby);
->
->-- 
->Richard Harter, Software Maintenance and Development Systems, Inc.
->Net address: jjmhome!smds!rh Phone: 508-369-7398 
->US Mail: SMDS Inc., PO Box 555, Concord MA 01742
->This sentence no verb.  This sentence short.  This signature done.

IMHO the many responders to this question gave the right answer to
perhaps the wrong question.  The issues is not how to write the macro,
but how to invoke it.

Change:

 if (foo==bar) A_MACRO(moby);
 else B_MACRO(gumby);

To:

 if (foo==bar){ A_MACRO(moby);}
 else {B_MACRO(gumby);}

and the problem goes away.  (Choose your own indenting style.)

Aside:
	The one that really gets me is when someone does:
	foo(gag) and you later discover that foo() is a macro.
	Unfortunately, ANSI C has some of these.  Is there a
	requirement that they are expressions?

Of course, you have to anticipate the possiblity of change when you
write the original code.  And if you are any good, you get it right
the first time :+) I mean :=) I mean :<), well, you know what I mean. :-)

Ken

martin@mwtech.UUCP (Martin Weitzel) (08/08/90)

In article <362.26be9dcc@astro.pc.ab.com> yoke@astro.pc.ab.com (Michael Yoke) writes:
[question about how to define multiple statement macros that can be used
 much like functions, esp. *require* a semicolon after their invocation]

My first recommendation: Don't write such macros, use a function.
My second recommendation: Same as first.

Still reading on? So you seem to be pretty sure that you *must*
do it with macro. So read my third recommendation, but read it
carefully and completly:

The trick is to embrace the statements with something that needs
a trailing semicolon. Basically, there are two such methods.

#define multi_stmt_macro1()  if (1) { put your stuff in here } else
or
#define multi_stmt_macro2()  do { put your stuff in here } while (0)

NOTE: In both cases you write *no* trailing semicolon in the #define.
So an invocation of this macro must supply the semicolon:

	multi_stmt_macro1() ;
or
	multi_stmt_macro2() ;

expands exactly to one execution of the statements you have written
in the definition.

There is one reason why the second form is preferable. Consider the
case, where you inadvertently forgot to supply the trailing semicolon.

	multi_stmt_macro1() /* ; forgotten here */
	x = y;

The following statement (here: x = y;) will *never* be executed (some
compilers and lint may warn you, but if you prefer `super-silent'
compilations - or lint-ations - you have possible put some fake-stuff
in or around your macro so that you still get no message). On the other
hand
	multi_stmt_macro2() /* ; forgotten here */
	x = y;

gives you what you deserve: A syntax error.

The above way to define a macro is the "most function-like" I know,
but it has still some drawbacks. The most important is that you
should DESCRIBE THE TRICK IN A COMMENT, so that the poor programmer
who has to maintain your code one day will not have too hard a time
to understand what you have done. 

Because of that I prefer using the trick in two steps, as the following
code excerpt shows:

/*
 * The following definitions of BMAC and EMAC are supplied for the
 * purpose to write multi statement macros that resemble true
 * functions as close as possible. Note that the flow-control
 * statments here have the sole purpose to require a trailing
 * semicolon after the invocation!
*/
#define BMAC do{
#define EMAC }while(0)
/*
 * Use BMAC to start the definition of a multi statement macro.
 * Use EMAC to end the definition: Here is an example:
 *
 * #define MULTI_STMT_MACRO(macro_parameters) BMAC\
 *	stmt;\
 *	stmt;\
 * EMAC
*/
 
................ many lines
................ may be here

#define A_MACRO() BMAC .............. EMAC

................. again many lines

#define B_MACRO(a,b) BMAC\
	............\
	............\
EMAC


The big advantage here comes when a later maintainer reads the code.
Generally, maintenance-reading may start anywhere in the middle, and
the programmer will eventually need to look what A_MACRO really does.
After locating the #define A_MACRO, he or she finds two other things
that are probably not known: BMAC and EMAC. Locating these two directly
stumps onto the comment which explains their purpose. So you have only
*one* place where you can put your explanations, even if you use the
trick several times. Furthermore, the example in the comment near the
definition of BMAC and EMAC will help a maintainer who reads the code
"top down" and encounters BMAC and EMAC before he or she has seen the
actual usage.

Finally some words to the wise: Those block macros are somehow
"poor man's inline function". They have all the disadvantages of
inline code (more space, no recursion, ... - of course they have
advantages too, otherwise you would not use them) *plus* the common
disadvantages of macros vs. functions. Besides that they may not
return a value important pitfalls are:

1) Macro arguments you write more than once in the replacement text
   are expanded more than once, so side effects may take place
   more than once, WHICH IS NOT AT ALL VISIBLE FROM THE INVOCATION!
   (We just tried to make the invocation look like a function.)
2) If you need local variables, you must avoid to give the same
   names as parameters in the invocation. (See following example).

As I allready recommended, such macros should not be used very often.
In fact, I can see only two places where they sometimes may be
desirable:

a) You have determined with some profiling tool that the overhead
   for a certain function call is too expensive compared to the
   work the function does and you want to "inline" the function
   code as painless as possible (or maybe choose between a true
   function and inlining with a #define Option at compile time).
b) You have a common algorithm which you want to make "type independent".

In both cases you should ensure that the invocation takes care to
avoid the pitfalls described under 1) and 2). I usually choose
upper-case-only names for such pseudo-functions. At least a moderatly
experienced later maintainer will be warned thru that, as C-functions
traditionally use lower-case-only or mixed-case names.

Finally I have a `real life' example for b) - hopefully without typos :-)

#define PRINTARRAY(fmt, npl, arr) BMAC\
int _i_ = 0;\
while (_i_ < sizeof arr / sizeof arr[0]) {\
	printf(fmt, arr[_i_]);\
	putchar((++_i_ % npl) ? ' ' : '\n');\
}\
EMAC

With this macro you can print any(%) array "arr" as long as it consists
of elements for which you can give a printf-format specifier "fmt".
You get "npl" elements per line (seperated by a blank). The only problem
with this is that you can NOT print an array named "_i_". (Of course
this is the reason why I gave the loop counter this strange name and
didn't call it "i" or somthing similar common.

%: Note that with `T a[100][200]' and `struct { T b[100]; } s'
PRINTARRAY still works for `a[33]' and `s.b', but that it fails
in more complex cases, eg. with `T z[100]' for `z + 1', which is
still valid for C, but produces a syntax error when it expands
to `sizeof z + 1 / sizeof z + 1[0]'. The syntax error could be
avoided by enclosing `arr' in brackets - as it is generally advisable
in macro replacement text - but in the above case I prefered the
failing over getting a completly meaningless results (meaningless
for my purpose). Of course, a clever programmer might specify `1 + z'
which causes no syntax error but will fool PRINTARRAY badly.
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

steve@taumet.com (Stephen Clamage) (08/08/90)

farrell@onedge.enet.dec.com (Bernard Farrell) writes:

|In article <10836@crdgw1.crd.ge.com>, volpe@underdog.crd.ge.com (Christopher R Volpe) writes...

|	if (blah)
|	{
|	    stmt1;
|	    stmt2;
|	};
|>           
|>Can someone with a copy of the Standard tell us if a semicolon is 
|>allowed? ...
|... I believe K&R (n) was probably placating Pascal converts, and meant
|no semicolon necessary.

The problem comes when you attach an "else" clause:
	if (blah)
	{
	    ...
	};
	else { ... }
The semicolon is illegal there (or the "else" is illegal, take your pick).

And of course, following the closing brace of a function with a
semicolon is illegal (in ANSI C).
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

ckp@grebyn.com (Checkpoint Technologies) (08/08/90)

In article <362.26be9dcc@astro.pc.ab.com> yoke@astro.pc.ab.com (Michael Yoke) writes:
>Could some of you give me your opinion on the best way to handle multiple 
>statement macros.
> [then asks about a multi-statement macro that works like a statement
>  ought to]

If each "statement" in the macro is really an "expression", then you can
use the comma operator to make them all into one expression, which then
serves as one statement.  This can even be used to make multi-expression
macros that appear (mostly) to be function calls as well, so long as you
can engineer the "return value" to be the last expression in the comma-
separated list.

I'll give an example of a macro I use a lot.  It's a derivative of
"strncpy" which assures a zero terminator on the destination (strncpy
doesn't) and which measures the destination length itself, using
sizeof:

#define STRMOV(dest,src) \
      ((void) strncpy(dest, src, sizeof(dest)-1), \
      dest[sizeof(dest)-1] = '\0', \
      dest)

Note three expressions, all separated by commas.  The result type and
value of the comma operator is the type and value of the second
expression, so the STRMOV macro "returns" the value "dest" of it's type.
(I actually use one that "returns" type "void"; the return value from
strncpy always puzzled me.)

Note also for this macro to work, the type of dest must be "array [known
size] of char", not "pointer to char" or "array [unspecified size] of
char".

Now this technique won't work if you really need multiple "statements",
which could include things like return, break, if, while, etc., but it
works just dandy for multiple expressions.
-- 
First comes the logo: C H E C K P O I N T  T E C H N O L O G I E S      / /  
                                                                    \\ / /    
Then, the disclaimer:  All expressed opinions are, indeed, opinions. \  / o
Now for the witty part:    I'm pink, therefore, I'm spam!             \/

brad@SSD.CSD.HARRIS.COM (Brad Appleton) (08/09/90)

In article <21057@grebyn.com> ckp@grebyn.UUCP (Checkpoint Technologies) writes:
>
>If each "statement" in the macro is really an "expression", then you can
>use the comma operator to make them all into one expression, which then
>serves as one statement.  This can even be used to make multi-expression
>macros that appear (mostly) to be function calls as well, so long as you
>can engineer the "return value" to be the last expression in the comma-
>separated list.
>
>Now this technique won't work if you really need multiple "statements",
>which could include things like return, break, if, while, etc., but it
>works just dandy for multiple expressions.

Glad to see a few people finally mentioned the comma operator! Another 
alternative along those same lines (with similar limitations) is to make
use of the logical operators || and &&. Using this, the following:

	#define CHECK(cond)  { if (cond)  exit(-1);  }

could be replaced by

	#define CHECK(cond)  ((cond) || exit(-1))

And wouldnt wreak havoc inside nested if statements.

As another example, if you didnt have the dup2() system call on your Unix
system and wanted to write a macro for it, you could use the following:

    #define  dup2(to,from)  ( (close(from) || (to = dup()) < 0) ? -1 : 0 )

If there is some reason why this would not give the same results as dup2()
(and fail for the same reasons) then let me know. The main problem I foresee
is that I cant have a file-descriptor numbered lower than `from' available
before I make the dup2() call.

Anyway, even if the results from the above are totally incorrect, it still
demonstrates the use of logical operators in macros.

Hope this helps!
______________________ "And miles to go before I sleep." ______________________
 Brad Appleton        brad@travis.ssd.csd.harris.com   Harris Computer Systems
                          ...!uunet!hcx1!brad          Fort Lauderdale, FL USA
~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~
______________________ "And miles to go before I sleep." ______________________
 Brad Appleton        brad@travis.ssd.csd.harris.com   Harris Computer Systems
                          ...!uunet!hcx1!brad          Fort Lauderdale, FL USA
~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~

karl@haddock.ima.isc.com (Karl Heuer) (08/09/90)

In article <5439@stpstn.UUCP> lerman@stpstn.UUCP (Ken Lerman) writes:
>IMHO the many responders to this question gave the right answer to
>perhaps the wrong question.  The issues is not how to write the macro,
>but how to invoke it.  [Put braces around it.]

Your solution needs to be done at each invocation, whereas the other responses
fix the problem at the source.  In the best case (when the macro can be
written as an expression that evaluates each argument exactly once), the user
doesn't even need to know it's a macro.  This is a plus.

>Aside:
>	The one that really gets me is when someone does:
>	foo(gag) and you later discover that foo() is a macro.
>	Unfortunately, ANSI C has some of these.  Is there a
>	requirement that they are expressions?

With very few exceptions%, any functions that the vendor chooses to implement
as macros must have the property described above.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint
________
% assert() must under-evaluate when NDEBUG is set.  getc() and putc() may
  over-evaluate the stream argument.  I can't think of any others.

karl@haddock.ima.isc.com (Karl Heuer) (08/09/90)

In article <642@travis.csd.harris.com> brad@SSD.CSD.HARRIS.COM (Brad Appleton) writes:
>	#define CHECK(cond)  ((cond) || exit(-1))

Won't work if exit() is properly declared as void.  Try one of
	#define CHECK(cond)  ((cond) ? exit(-1) : (void)0)
	#define CHECK(cond)  ((cond) || (exit(-1), 0))

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

gvr@cs.brown.edu (George V. Reilly) (08/09/90)

In article <17298@haddock.ima.isc.com> karl@kelp.ima.isc.com (Karl Heuer) writes:
! %   In article <642@travis.csd.harris.com> brad@SSD.CSD.HARRIS.COM (Brad Appleton) writes:
! %    Glad to see a few people finally mentioned the comma operator! Another 
! %    alternative along those same lines (with similar limitations) is to make
! %    use of the logical operators || and &&. Using this, the following:
! %    
! %    	#define CHECK(cond)  { if (cond)  exit(-1);  }
! %    
! %    could be replaced by
! %    
! %    	#define CHECK(cond)  ((cond) || exit(-1))
! %    
! Won't work if exit() is properly declared as void.  Try one of
! 	#define CHECK(cond)  ((cond) ? exit(-1) : (void)0)
! 	#define CHECK(cond)  ((cond) || (exit(-1), 0))
! 

Ah, but Karl, you missed the more important bug that Brad should have
used &&, not ||.  In Brad's example, exit() will only be called if
cond == 0, which is exactly the inverse of what is desired.  The same is
true of your second offering.
________________
George V. Reilly			gvr@cs.brown.edu
uunet!brunix!gvr   gvr@browncs.bitnet	Box 1910, Brown U, Prov, RI 02912

diamond@tkou02.enet.dec.com (diamond@tkovoa) (08/09/90)

In article <14363@shlump.nac.dec.com> farrell@onedge.enet.dec.com (Bernard Farrell) writes:
>In article <10836@crdgw1.crd.ge.com>, volpe@underdog.crd.ge.com (Christopher R Volpe) writes...
[  if (blah) { stmt1; stmt2; };  ]
>>Can someone with a copy of the Standard tell us if a semicolon is 
>>allowed?
>The Standard simply comments on the Null statement in 3.6.3 as one that
>"performs no operations".   There is no reference to Null statements in
>the context of Block statements, 3.6.2., nor would I expect there
>to be because the fact that the statement has a curly brace in front of
>it really shouldn't modify it's meaning.

That semicolon is allowed.  There is an "if" statement followed by a null
statement.  The problem is that the USER might have intended that to be
only half of an "if" statement.  The user might have an "else" following:
  if (blah) MACRO; else JUNK;
The user does not expect an error message for the "else".

Coders of macros should make it easier for users -- just like libraries,
programming languages, editors, and other tools that will be used by
many more people than the developers.  So the following is common:
  #define MACRO  do { some_statement; more_statements; } while 0
Of course, if the statements can be written as expressions, then it
is preferable to make the macro into a comma (or similar) expression.

>I believe K&R (n) was probably placating Pascal converts, and meant
>no semicolon necessary.

Huh?  In
  if (blah) { stmt1; stmt2; } /* try a ; here? */ else stmt3;
a semicolon CANNOT be put there.

Both Pascal and C have null statements.
Both Pascal and C programmers criticize each other's language for style
of semicolon usage, both make errors and write false criticisms, and
both overlook shortcomings in their own languages.  In order to placate
correct criticisms, both languages could use some adjustments (which in
some cases were proposed and rejected).
-- 
Norman Diamond, Nihon DEC     diamond@tkou02.enet.dec.com
This is me speaking.  If you want to hear the company speak, you need DECtalk.

maart@cs.vu.nl (Maarten Litmaath) (08/09/90)

In article <642@travis.csd.harris.com>,
	brad@SSD.CSD.HARRIS.COM (Brad Appleton) writes:
)...
)As another example, if you didnt have the dup2() system call on your Unix
)system and wanted to write a macro for it, you could use the following:
)
)    #define  dup2(to,from)  ( (close(from) || (to = dup()) < 0) ? -1 : 0 )
)
)If there is some reason why this would not give the same results as dup2()
)(and fail for the same reasons) then let me know. The main problem I foresee
)is that I cant have a file-descriptor numbered lower than `from' available
)before I make the dup2() call.

The main problem is your definition being wrong.  Try the following instead:

	#define	dup2(from, to)	(close(to), dup(from))

It still fails if to == from.  This probably gets it right:

	#include	<sys/errno.h>

	#define	MAXFD	19	/* archaic */

	int	dup2(from, to)
	int	from, to;
	{
		int	fds[MAXFD + 1];
		register	int	*fdp = fds, fd;
		extern	int	errno;

		if (from < 0 || from > MAXFD || to < 0 || to > MAXFD) {
			errno = EBADF;
			return -1;
		}

		if (from == to)
			return to;

		while ((fd = *fdp++ = dup(from)) < to && fd >= 0)
			;

		if (fd != to) {
			close(to);
			(void) dup(from);
			if (fd < 0)
				--fdp;
		}

		while (fdp > fds)
			close(*--fdp);

		return to;
	}
--
   "UNIX was never designed to keep people from doing stupid things, because
    that policy would also keep them from doing clever things."  (Doug Gwyn)

volpe@underdog.crd.ge.com (Christopher R Volpe) (08/09/90)

In article <46860@brunix.UUCP>, gvr@cs.brown.edu (George V. Reilly) writes:
|>Ah, but Karl, you missed the more important bug that Brad should have
|>used &&, not ||.  In Brad's example, exit() will only be called if
|>cond == 0, which is exactly the inverse of what is desired.  The same is
|>true of your second offering.

What makes you think that is what was desired? I interpret "CHECK(cond)"
the same way I interpret "ASSERT(cond)", which is "continue iff cond is true".
I.e., exit when cond is false. Under this interpretation, "||" is correct.

|>________________
|>George V. Reilly			gvr@cs.brown.edu
|>uunet!brunix!gvr   gvr@browncs.bitnet	Box 1910, Brown U, Prov, RI 02912
                        
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

steve@taumet.com (Stephen Clamage) (08/09/90)

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:

>>  [asks about defining macros that expand to more than one statement]

>I wasn't going to reply to this, but the Official Free Answer[*] is
>to use the expansion
>	do { /* your statements go here */ } while (0)
>This will work in any context where a statement is allowed; it wants
>a semi-colon after it just like a simple function call would.

But doesn't work in expression contexts.  One of the many problems
("gotchas") with macros is that while it may look like a function
call, it may not be.  If we have a macro
	#define foo(a, b) do { ........... } while (0)
there is a temptation to use it like
	m = k + foo(i, j) / n;
The compiler will reject this with an error message which may be hard to
relate to the code as written.

On that basis, I prefer a macro written as an expression, where possible.
Use comma-expressions, and enclose the whole thing in parens.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

steve@taumet.com (Stephen Clamage) (08/09/90)

ckp@grebyn.com (Checkpoint Technologies) writes:

[ shows how to make up a macro with expressions, rather than statements ]

>Now this technique won't work if you really need multiple "statements",
>which could include things like return, break, if, while, etc., but it
>works just dandy for multiple expressions.

Actually, you can handle "if" statements by transforming them into
conditional expressions (c ? expr1 : expr2).  As long as neither the
"then" nor "else" clause contains "for", "while", "switch", "break",
or "goto", you can always do this, though it is occasionally awkward.
(I don't claim that you will always want to, just that you can.)
If there is no "else", just use zero for the second expression.
You will usually need to cast each expression to void to satisfy the
constraint of the conditional expression that each half must evaluate
to the same type.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

hp@vmars.tuwien.ac.at (Peter Holzer) (08/09/90)

volpe@underdog.crd.ge.com (Christopher R Volpe) writes:

>In article <46860@brunix.UUCP>, gvr@cs.brown.edu (George V. Reilly) writes:
>|>Ah, but Karl, you missed the more important bug that Brad should have
>|>used &&, not ||.  In Brad's example, exit() will only be called if
>|>cond == 0, which is exactly the inverse of what is desired.  The same is
>|>true of your second offering.

>What makes you think that is what was desired? I interpret "CHECK(cond)"
>the same way I interpret "ASSERT(cond)", which is "continue iff cond is true".
>I.e., exit when cond is false. Under this interpretation, "||" is correct.

What made ME think that this s what was desired is this line in the original 
posting:
From: brad@SSD.CSD.HARRIS.COM (Brad Appleton)
> 
> 	#define CHECK(cond)  { if (cond)  exit(-1);  }
> 
which is certainly not equivalent to:
> 
> 	#define CHECK(cond)  ((cond) || exit(-1))
> 
but to
#define CHECK(cond)  ((cond) && exit(-1))

Karl obviously interpreted it the same way or he would not have
suggested:

From: karl@haddock.ima.isc.com (Karl Heuer)
>	#define CHECK(cond)  ((cond) ? exit(-1) : (void)0)

It is amazing though, that the Walking Lint missed the ||-&& confusion.
Oh well, the program would miss it too :-)
--
|    _	| Peter J. Holzer			| Think of it	|
| |_|_)	| Technische Universitaet Wien		| as evolution	|
| | |	| hp@vmars.tuwien.ac.at			| in action!	|
| __/  	| ...!uunet!mcsun!tuvie!vmars!hp	|     Tony Rand	|

steve@taumet.com (Stephen Clamage) (08/09/90)

gg10@prism.gatech.EDU (GALLOWAY) writes:
>Why doesn't this work?

>#define A_MACRO(bar, baz)  func1(bar), func2(baz)

>I have been using syntax like this for awhile, is this wrong or unportable?

You need an extra set of parens:
	#define A_MACRO(bar, baz)  ( func1(bar), func2(baz) )
Look what happens without the parens:
	i = A_MACRO(3, 4) + 2;
becomes:
	i = func1(3), func2(4) + 2;
which is the same as
	(i = func1(3)), (func2(4) + 2);
which is probably not what was meant.  With parens, it becomes;
	i = (func1(3), func2(4)) + 2;
which may or may not be what was meant, but at least the +2 is not discarded.

If the do { ... } while(0) construct was used instead, the above
expression becomes illegal, which may or may not be what was intended.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

brad@SSD.CSD.HARRIS.COM (Brad Appleton) (08/10/90)

In article <46860@brunix.UUCP> gvr@cs.brown.edu (George V. Reilly) writes:
>! %    	#define CHECK(cond)  { if (cond)  exit(-1);  }
>! %    could be replaced by
>! %    	#define CHECK(cond)  ((cond) || exit(-1))
>! %    
>Ah, but Karl, you missed the more important bug that Brad should have
>used &&, not ||.  In Brad's example, exit() will only be called if
>cond == 0, which is exactly the inverse of what is desired.  The same is
>true of your second offering.

Actually, it was the IF statement I messed up, not the "||". I want the program
to exit only if the condition is false (like an assertion).

Sorry about that!
I was more concerned with illustrating a (possibly new) technique and didnt
pay close enough attention to the example I used. The dup2() macro that I
posted in the same article I have used before (succesfully).

Actually, that dup2() macro is in a small piece of code that I wrote
specifically for illustrating how to fork off a process and have the parent
read the output from the child. It seems to be asked frequently (even though
it is Unix specific). Should I submit my file to the FAQ list?

______________________ "And miles to go before I sleep." ______________________
 Brad Appleton        brad@travis.ssd.csd.harris.com   Harris Computer Systems
                          ...!uunet!hcx1!brad          Fort Lauderdale, FL USA
~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~

mcdaniel@adi.com (Tim McDaniel) (08/10/90)

martin@mwtech.UUCP (Martin Weitzel) writes:
> As I allready recommended, such macros should not be used very often.
> In fact, I can see only two places where they sometimes may be
> desirable:

c) You need to do something which is impossible without use of the
   preprocessor.  The canonical example is an "assert(x)" that does
   not evaluate its argument at all if assertion checking is turned
   off.

d) You want to make some kind of syntax change to the language.  This
   should be done with EXTREME care!  (The canonical counterexample is
   the original, damn near unreadable, Bourne shell source code.)

   Our example is "MESSAGE(fooBar);" which expands to
      char fooBar = "fooBar";
   In that way, we can
   1) do
         formatMessage(fooBar, ...);
      to get the same effect as
         formatMessage("fooBar", ...);
   2) get a compile-time error rather than a run-time error if we
      make a typo in a message name.
   3) in another section do a check like
         if (message == fooBar) ...	/* pointer equality */
      rather than
         if (!strcmp(message, "fooBar")) ... /* string equality */
--
"I'm not a nerd -- I'm 'socially challenged'."

Tim McDaniel
Internet: mcdaniel@adi.com             UUCP: {uunet,sharkey}!amara!mcdaniel

karl@haddock.ima.isc.com (Karl Heuer) (08/10/90)

The source of the problem is the name of the macro.  It's not at all clear
whether `CHECK' should mean `assert' or `forbid'.

In article <1752@tuvie> hp@vmars.tuwien.ac.at (Peter Holzer) writes:
>Karl obviously interpreted it the same way [as a `forbid' macro]

I noticed that the `||' version had the `assert' semantics, which I retained
in my second example (which I actually wrote first), assuming this was the
intent.  I then wrote the `?:' version while looking at the `if' version of
the original.  I even checked it against the copy in <assert.h>, noting that
the operands were in the opposite order, which I accepted because the `if'
version did indeed have the semantics of `forbid' rather than `assert'.  It
completely slipped my mind that I'd just made the opposite observation a
minute earlier!

>It is amazing though, that the Walking Lint missed the ||-&& confusion.

What I missed was that the two versions were inconsistent--I actually had the
right model for `a || b' in mind.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

scc@rlgvax.UUCP (Stephen Carlson) (08/11/90)

In article <3526@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
>I wasn't going to reply to this, but the Official Free Answer[*] is
>to use the expansion
>	do { /* your statements go here */ } while (0)
>This will work in any context where a statement is allowed; it wants
>a semi-colon after it just like a simple function call would.

Another way is:
	if (1) { /* your statements go here */ } else

This is just as valid as the do { ... } while(0) trick.  The semicolon would
terminate the else with a null statement, and the else avoids a dangling else
problem:
	if (cond)
		if (1) { ... } else ;
	else
		...

As a matter of style, I prefer to define statement-like macros that have no
arguments with an empty set of parenthesis:
	#define FOO() if (1) { int a; bar(&a); } else
and invoke it with
	FOO();
anywhere a statement is valid.  This has more of the feel of a function
call.  Although this works (a #define with 0 arguments) with every
preprocessor I've ever used, is there any official sanction for this
construct?
-- 
Stephen Carlson            | ICL OFFICEPOWER Center
scc@rlgvax.opcr.icl.com    | 11490 Commerce Park Drive
..!uunet!rlgvax!scc        | Reston, VA  22091

staff@cadlab.sublink.ORG (Alex Martelli) (08/13/90)

brad@SSD.CSD.HARRIS.COM (Brad Appleton) writes:
...[some details omitted]...
>use of the logical operators || and &&. Using this, the following:
>	#define CHECK(cond)  { if (cond)  exit(-1);  }
>could be replaced by
>	#define CHECK(cond)  ((cond) || exit(-1))
>And wouldnt wreak havoc inside nested if statements.

Another technique I like for this very situation:

#define CHECK(cond) if(cond) exit(-1); else

...no havoc-wrecking here, either, and also work fine for cases where
the conditional action is, say, "return FAILURE_INDICATOR;" - AND no
lint complaints about constants in conditional contexts.  Only good for
CONDITIONAL macros, alas...

-- 
Alex Martelli - CAD.LAB s.p.a., v. Stalingrado 45, Bologna, Italia
Email: (work:) staff@cadlab.sublink.org, (home:) alex@am.sublink.org
Phone: (work:) ++39 (51) 371099, (home:) ++39 (51) 250434; 
Fax: ++39 (51) 366964 (work only; any time of day or night).

karl@haddock.ima.isc.com (Karl Heuer) (08/13/90)

In article <1316@rlgvax.UUCP> scc@rlgvax.OPCR.ICL.COM (Stephen Carlson) writes:
>Although this works (a #define with 0 arguments) with every preprocessor I've
>ever used, is there any official sanction for this construct?

Certainly; `getchar()' is the classic example.  ANSI explicitly allows it too.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint