🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.lang.c.moderated
2 messages
2 total messages Started by Chris Torek Mon, 25 Mar 1996 12:23
Re: Macros and Braces
#2388
Author: 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
Re: Macros and Braces
#2431
Author: Christopher R Volpe
Date: Fri, 29 Mar 1996 12:08
42 lines
2228 bytes
Chris Torek wrote:
> 
> In article <4j06iu$7qm@solutions.solon.com> 100576.1776@compuserve.com writes:
> 
[...]
> >#define TRACE(s)                                    \
> >  if (trace_on)                                     \
> >    fprintf(trace_file, __FILE__ __LINE__ "%s", s);
> 
[...]
> 
> 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).
> 

Ok, I must be missing something here. Chris T. is making an "efficiency
improvement" on code that doesn't look to me like it should compile in
the first place. The original code presumes that __LINE__ expands to a
string literal, which it does not. Apparently (and I would be shocked if
this were not the case) Chris T. knows this, as evidenced by the fact
that he used "%d" and not "%s" for the __LINE__ parameter in his fprintf
call. So why didn't he catch and point out such an obvious error? 

Did TC1 decree that integral constant expressions that appear lexically
adjacent to string literals shall be evaluated and stringized in order
to allow subsequent string literal concatenation?

--

Chris Volpe				Phone: (518) 387-7766 (Dial Comm 8*833
GE Corporate R&D			Fax:   (518) 387-6560
PO Box 8, Schenectady, NY 12301		Email: volpecr@crd.ge.com
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads