Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 25 Feb 2000 23:49:09 -0800
From:      Alfred Perlstein <bright@wintelcom.net>
To:        cjclark@home.com
Cc:        Marco Molteni <molter@csl.sri.com>, freebsd-chat@FreeBSD.ORG
Subject:   Re: how to do this C preprocessor trick?
Message-ID:  <20000225234909.W21720@fw.wintelcom.net>
In-Reply-To: <20000226003741.C20702@cc942873-a.ewndsr1.nj.home.com>; from cjc@cc942873-a.ewndsr1.nj.home.com on Sat, Feb 26, 2000 at 12:37:41AM -0500
References:  <20000225182432.A5017@sofia.csl.sri.com> <20000226001121.A20702@cc942873-a.ewndsr1.nj.home.com> <20000225214616.U21720@fw.wintelcom.net> <20000226003741.C20702@cc942873-a.ewndsr1.nj.home.com>

next in thread | previous in thread | raw e-mail | index | archive | help
* Crist J. Clark <cjc@cc942873-a.ewndsr1.nj.home.com> [000225 22:02] wrote:
> On Fri, Feb 25, 2000 at 09:46:17PM -0800, Alfred Perlstein wrote:
> > * Crist J. Clark <cjc@cc942873-a.ewndsr1.nj.home.com> [000225 21:36] wrote:
> > > On Fri, Feb 25, 2000 at 06:24:32PM -0800, Marco Molteni wrote:
> > > > Hi all,
> > > > 
> > > > I have a function that takes a variable number of arguments:
> > > > 
> > > >     void d_printf(const char *format, ...)
> > > > 
> > > > I would like to make it print automatically the function name 
> > > > from which it is called, eg instead of doing
> > > > 
> > > >     f() { d_printf("f: blabla", x, y, z); }
> > > > 
> > > > doing simply
> > > > 
> > > >     f() { d_printf("blabla", x, y, z); }
> > > > 
> > > > To do that, I though of wrapping d_printf() around a macro like
> > > > 
> > > >     #define dprintf(x) d_printf(__FUNCTION__, x)
> > > > 
> > > > but whatever combination I use (also with #), the thing is not going to work:
> > > > 
> > > >     main.c:231: macro `d_printf' used with too many (4) args
> > > > 
> > > > Is it possible to trick the C preprocessor to do what I want?
> > > 
> > > Yeah, I use the same type of thing to produce error messages. I'm
> > > having a little bit of trouble understanding exactly what you are
> > > trying to do above, so I'll just show my solution to my problem.
> > > 
> > > I wanted to just be able to do,
> > > 
> > >   errmsg(char fmt, ...)
> > > 
> > > But have it print,
> > > 
> > >   cmd(file:line)- Error message
> > > 
> > > Where 'cmd' is the name of the program (the tail of argv[0]), 'file'
> > > is the C source file name, and 'num' is the line number.
> > > 
> > >   char *cmd
> > > 
> > >   void _errmsg(char *fmt, ... )
> > >   {
> > >     va_list ap;
> > > 
> > >     va_start(ap,fmt);
> > >     vfprintf(stderr,fmt,ap);
> > >     va_end(ap);
> > >   }
> > > 
> > >   #define errmsg  fprintf(stderr,"%s(%s:%d)- ",cmd,__FILE__,__LINE__); _errmsg
> > > 
> > > 
> > > Gets me around the varargs in the precompiler by not using _any_
> > > args in the macro. So,
> > > 
> > >   errmsg("cannot fine file: %s\n",str);
> > > 
> > > Expands to,
> > > 
> > >   fprintf(stderr,"%s(%s:%d)- ",cmd,__FILE__,__LINE__); _errmsg("cannot fine file: %s\n",str);
> > > 
> > > And you know, it works. Big help in debugging big apps. When it's sent
> > > bound for users, I make the messages a bit less verbose, but only
> > > takes the one change.
> > 
> > One of the nasty side effects is that this makes the macro expand to
> > multiple statements.
> > 
> > what's so bad about that?
> > 
> > if (foo < 0)
> > 	errmsg("foo < 0");
> > 
> > Macros that expand to multiple statements ought to be enclosed in a
> > do { } while(0) loop.
> > 
> > Although the extra parens are ugly, it things a bit safer/cleaner.
> 
> Why a,
> 
>   do { <stuff> } while(0)
> 
> Rather than just,
> 
>   { <stuff> }

I really don't remeber offhand, I know a lot of macros in FreeBSD
are moved from 

#define foo { bar; baz; }

to

#define foo do{ bar; baz; }while(0)

I think it has to do with the fact that '{ .. }' is not a statement,
but a block, it will break in certain constructs.

Check the commitlogs and cross reference the code that was fixed by
macros being changed to do/while in the tree.

> That's how I group multi-statement macros, but that does not work for
> this one.

You should use do/while

> 
> I just saw your answer and I guess it boils down to which is more ugly
> and which is easier to forget to do properly,
> 
> Yours,
> 
>   d_printf((fmt,arg1,arg2));
> 
> Or mine,
> 
>   { d_printf(fmt,arg1,arg2); }
> 
> Extra pair of parenthesis or extra pair of curly brackets? ;)
> 
> Or am I overlooking another vulnerability?

It's easy to forget the braces and it will slip by most likely without
a compile time warning, it's safer to do it our way.

-- 
-Alfred Perlstein - [bright@wintelcom.net|alfred@freebsd.org]


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-chat" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20000225234909.W21720>