🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.c.moderated
Article #2388

Re: Macros and Braces

#2388
From: Chris Torek
Date: Mon, 25 Mar 1996 12:23
107 lines
3614 bytes
In article <4j06iu$7qm@solutions.solon.com> 100576.1776@compuserve.com writes:

[wants to replace]

>#define CLEAR_ERROR(e) { \
>  (e).a = 0;             \
>  (e).b = 0;             \
>  (e).c = 0;             \
>  TRACE("clear error");  \
>}
>#define TRACE(s)                                    \
>  if (trace_on)                                     \
>    fprintf(trace_file, __FILE__ __LINE__ "%s", s);

[with something that does not add an `extra' semicolon, making

	if (expr)
		CLEAR_ERROR(e);
	else
		...

fail.]

>As I said at the top, I am sure that I am not the first with this
>problem and would love to hear of THE clean solution.  Thanks very much.

There is no `the' solution, but there are plenty of `a' solutions.

OPTION A: decree that this is a macro and acts funny; always write
either:

	if (expr) {
		CLEAR_ERROR(e);
	} else
		...

or the vaguely C-like:

	if (expr)
		CLEAR_ERROR(e)	/* NO SEMICOLON HERE */
	else
		...

Drawbacks: obvious.


OPTION B: convert everything to expressions (use ?: for TRACE):

	#define CLEAR_ERROR(e) \
		((e).a = (e).b = (e).c = 0, TRACE("clear error"))
	#define TRACE(s) \
		(trace_on ? \
		 fprintf(trace_file, "%s:%d: %s", __FILE__, __LINE__, s) : 0)

(I pulled the __FILE__ and __LINE__ expressions apart so that a
quality compiler can emit a single string constant for __FILE__,
which could save dozens of Kbytes of text space, depending on how
you use the macro).

Drawbacks: almost none (but note that you cannot declare local
variables, since there are no blocks).


OPTION C: use the `magic wrapper' that converts arbitrary brace-
enclosed code into a single statement:

	#define CLEAR_ERROR(e) \
		do { \
			(e).a = 0; \
			(e).b = 0; \
			(e).c = 0; \
			TRACE("clear error"); \
		} while (0)

	#define TRACE(s) \
		do { \
			if (trace_on) \
				fprintf( ... ); \
		} while (0)

Drawbacks: the macros look funny, and may elicit a warning (`constant
in conditional context' or similar) for the `while (0)' part.  The
resulting macro is still a statement, not an expression, and
something like `return CLEAR_ERROR(e), 3' will fail.


OPTION D: use special compiler extensions such as gcc's ({ ... })
construct.  Drawbacks: obvious.

OPTION E: put the clearing and/or tracing into functions so that
they really are expressions (e.g., define `CLEAR_ERROR(e)' as
clr_err(&(e)), and TRACE(s) as trace(s, __FILE__, __LINE__)).
Drawback: possibly, slower code; advantage: possibly, smaller/faster
code.  (This one is tricky!  Inline expansion usually leads to
larger but faster code.  With modern caching systems, however, the
smaller code may fit entirely in the cache, and cached code runs
approximately an order of magnitude faster, easily offseting any
losses from subroutine calls.  Your best bet is to write the simplest
and clearest code you can to start with, then profile and tune if
necessary.)

No doubt there are more options.  Some of these can be used together
(e.g., replace TRACE with a true function, and write CLEAR_ERROR as
a comma-expression).
-- 
In-Real-Life: Chris Torek, Berkeley Software Design Inc
El Cerrito, CA	Domain:	torek@bsdi.com	+1 510 234 3167
Technical Details
Message-ID: <4j637g$3i6@solutions.solon.com>
Path: arc1-ca.pugleaf.net!solon.com!not-for-mail

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!solon.com!not-for-mail
From: Chris Torek <torek@elf.bsdi.com>
Newsgroups: comp.lang.c.moderated
Subject: Re: Macros and Braces
Date: 25 Mar 1996 06:23:12 -0600
Organization: Berkeley Software Design, Inc.
Sender: clc@solutions.solon.com
Approved: clc@solutions.solon.com
Message-ID: <4j637g$3i6@solutions.solon.com>
NNTP-Posting-Host: solutions.solon.com