🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

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

Macros and Braces

#2355
From: Antony Pace (UK/CH)
Date: Sat, 23 Mar 1996 06:43
126 lines
3495 bytes
Hi all,

I am having problems writing a macro (Ansi C) for which I feel there
must be standard technique.  Can anyone help?


Here is my first attempt at the macro.  I have defined an error type
which is a small structure with 3 variables in it.  I want to use a
macro to clear all the variables so that if the number or type of
variables change, only my macro has to change.

typedef struct {
  int a;
  int b;
  int c;
} t_error;


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


TRACE is a macro provided by another module which is approximately:

#define TRACE(s)                                    \
  if (trace_on)                                     \
    fprintf(trace_file, __FILE__ __LINE__ "%s", s);

Now, when I use my CLEAR_ERROR macro in code it works ok.

void my_fn(void) {
  t_error error;

  CLEAR_ERROR(error);
  ...
}

Note how the semicolon I put after the invocation becomes a null
statement.  I expect users of my CLEAR_ERROR macro to use it, as then
the macro looks like a function call.

In this code segment, my macro does not work:

  ...
  if (a==3)
    CLEAR_ERROR(error);
  else
    b=5;
  ...


This expands to:

  ...
  if (a==3) {
    (e).a = 0;
    (e).b = 0;
    (e).c = 0;
    TRACE("clear error");
  }
  ;   /* note the null statement */
  else
    b=5;
  ...

Of course I get an error 'else' has no 'if'.
----------------------------------------------------

Second part!

Now normally in this situation I would either combine the macro
statements to make a single statement by using the comma expression, or
I would call a function from the macro.


The comma expression
--------------------

#define CLEAR_ERROR(e)  \
  (e).a = 0, (e).b = 0 ,  (e).c = 0 , TRACE("clear error")

which expands to 

  (e).a = 0, (e).b = 0 ,  (e).c = 0 ,  if (trace_on)
    fprintf(trace_file, __FILE__ __LINE__ "%s", "clear error")
  ;

The semicolon is now a statement separator and not a null statement, but
the TRACE expands to an if statement which does not work with the comma
expression.

The function call
-----------------

#define CLEAR_ERROR(e) \
  clear_error(e)

void clear_error(t_error error) {
  (error).a = 0;            
  (error).b = 0;           
  (error).c = 0;           
  TRACE("clear error");
}

But not here what the TRACE puts in the trace file for the __FILE__ and
__LINE__ numbers.  Of course it is always the same file and line.

I could just put the variable clearing in the function but then I still
have two statements in the macro and that is no better than having four.

My current implementation looks like this.

#define CLEAR_ERROR(e) \
  if (!((e).a = (e).b = (e).c = 0)) TRACE("clear error")

It uses an unnecessary comparison which I don't like but at least it
works!

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.

Ant
Technical Details
Message-ID: <4j06iu$7qm@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: 100576.1776@compuserve.com (Antony Pace (UK/CH))
Newsgroups: comp.lang.c.moderated
Subject: Macros and Braces
Date: 23 Mar 1996 00:43:42 -0600
Organization: CompuServe Incorporated
Sender: clc@solutions.solon.com
Approved: clc@solutions.solon.com
Message-ID: <4j06iu$7qm@solutions.solon.com>
NNTP-Posting-Host: solutions.solon.com
X-Newsreader: OUI 1.3.0