variadic macros and and empty replacement for __VA_ARGS__

U

Urs Thuermann

I want to write a macro that produces debug output and has a variable
number of arguments, so that I can use like this:

int i;
char *s;

DBG("simple message\n");
DBG("message with an int argument, value is %d\n", i);
DBG("two arguments: int %d, strings %s\n", i, s);

The output should be a fixed prefix, say "DEBUG ", followed by the
function name the macros is used in, and then by the string passed to
the macro, including further arguments.

The best solution I have found so far, is

#define DBG(fmt, ...) printf("DEBUG %s:" fmt, __func__, __VA_ARGS__)

This works as intended as long as there is at least one argument
following the format strings, but it expands to
printf("DEBUG %s:" fmt, __func__,) when there is no argument and that
causes a syntax error.

The draft of C99 I have here, disallows to give no arguments for the
ellipsis ... as stated in 6.10.3:

[#4] If the identifier-list in the macro definition does not end
with an ellipsis, the number of arguments, including those
arguments consisting of no preprocessing tokens, in an invocation
of a function-like macro shall agree with the number of parameters
in the macro definition. Otherwise, there shall be more arguments
in the invocation than there are parameters in the macro
definition (excluding the ...). There shall exist a )
preprocessing token that terminates the invocation.


Is there a better way to write the DBG() macro to avoid this?

urs
 
J

John Devereux

Urs Thuermann said:
I want to write a macro that produces debug output and has a variable
number of arguments, so that I can use like this:

int i;
char *s;

DBG("simple message\n");
DBG("message with an int argument, value is %d\n", i);
DBG("two arguments: int %d, strings %s\n", i, s);

The output should be a fixed prefix, say "DEBUG ", followed by the
function name the macros is used in, and then by the string passed to
the macro, including further arguments.

The best solution I have found so far, is

#define DBG(fmt, ...) printf("DEBUG %s:" fmt, __func__, __VA_ARGS__)
Is there a better way to write the DBG() macro to avoid this?


There was a related thread a couple of weeks ago:

<http://groups.google.co.uk/group/co...oup:comp.lang.c&rnum=3&hl=en#949239c624c9fe71>

This basically used a *function* instead of a macro. The logging
function accepts variadic arguments, and these can then be modified
and passed on to a varargs form of printf (e.g. vfprintf).
 
R

Richard G. Riley

There was a related thread a couple of weeks ago:

<http://groups.google.co.uk/group/co...oup:comp.lang.c&rnum=3&hl=en#949239c624c9fe71>

This basically used a *function* instead of a macro. The logging
function accepts variadic arguments, and these can then be modified
and passed on to a varargs form of printf (e.g. vfprintf).

One little thing you might consider at an early stage : have an
importance or category enum as the first/second parameter : very
useful for filtering/enabling/disabling runtime logging for different
subsets in a non trivial system. You might even use the function name
and have settings to enable/disable logging for the particular function.
 
R

raxip

This works as intended as long as there is at least one argument
following the format strings, but it expands to
printf("DEBUG %s:" fmt, __func__,) when there is no argument and that
causes a syntax error.

#define macroFunc(a,b,...) ( Func(a, b, ##__VA_ARGS__) )
 
D

Default User

raxip said:
Assumptions are wonderous creatures.

That's nice. What does it have to do with anything? See my .sig below
for valuable information.



Brian
 
D

Default User

raxip said:
Is this better?

Somewhat. Where are the attributions (the who said what part)? I know
that Google puts them in if you use the correct Reply.



Brian
 
G

Guest

Michael said:
This is "gcc-C".
It is not valid C99, though.

I believe it can be valid C99 if the result of macroFunc(...) is
stringized, and __VA_ARGS__ is empty. (Of course, in that case, it's
useless and doesn't answer the question.)

As for the original question, I had taken a look at a non-GCC way of
writing ,##__VA_ARGS__ earlier. I don't recommend anyone actually use
this for hopefully obvious reasons, but in case anyone cares, here it
is. Please let me know if there are bugs in it (there may well be).

#include <stdio.h>

#define CONCAT(x, y) CONCAT_(x, y)
#define CONCAT_(x, y) x##y

#define ID(...) __VA_ARGS__

#define IFMULTIARG(if,then,else) \
CONCAT(IFMULTIARG_, IFMULTIARG_(if, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 0, ))(then,else)
#define IFMULTIARG_(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, \
_10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \
_20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \
_30, _31, _32, _33, _34, _35, _36, _37, _38, _39, \
_40, _41, _42, _43, _44, _45, _46, _47, _48, _49, \
_50, _51, _52, _53, _54, _55, _56, _57, _58, _59, \
_60, _61, _62, _63, ...) _63
#define IFMULTIARG_0(then, else) else
#define IFMULTIARG_1(then, else) then

#define PROVIDE_SECOND_ARGUMENT(x, ...) \
CONCAT(IFMULTIARG(ID(__VA_ARGS__), INSERT_, ADD_), \
SECOND_ARGUMENT) (x, __VA_ARGS__)
#define ADD_SECOND_ARGUMENT(x, y) y, x
#define INSERT_SECOND_ARGUMENT(x, y, ...) y, x, __VA_ARGS__

#define DEBUG(...) printf("DEBUG %s: " \
PROVIDE_SECOND_ARGUMENT(__func__, __VA_ARGS__))

int main() {
DEBUG("1\n");
DEBUG("%d\n", 2);
DEBUG("%d %d\n", 1, 2);
}
 
P

Peter Shaggy Haywood

Groovy hepcat Urs Thuermann was jivin' on 27 Mar 2006 15:34:46 +0200
in comp.lang.c.
variadic macros and and empty replacement for __VA_ARGS__'s a cool
scene! Dig it!
I want to write a macro that produces debug output and has a variable
number of arguments, so that I can use like this:

int i;
char *s;

DBG("simple message\n");
DBG("message with an int argument, value is %d\n", i);
DBG("two arguments: int %d, strings %s\n", i, s);

The output should be a fixed prefix, say "DEBUG ", followed by the
function name the macros is used in, and then by the string passed to
the macro, including further arguments.

I think this should work:

#define DBG(...) printf("DEBUG $s: ", __func__), printf(__VA_ARGS__)

--

Dig the even newer still, yet more improved, sig!

http://alphalink.com.au/~phaywood/
"Ain't I'm a dog?" - Ronny Self, Ain't I'm a Dog, written by G. Sherry & W. Walker.
I know it's not "technically correct" English; but since when was rock & roll "technically correct"?
 
U

Urs Thuermann

I think this should work:
#define DBG(...) printf("DEBUG $s: ", __func__), printf(__VA_ARGS__)

This is the first answer in this thread, which seems to understand my
post and solves the problem of inserting the __func__ between the fmt
and __VA_ARGS__ without having the ,) when __VA_ARGS__ is empty.

I wanted to avoid calling printf() twice, because I need this in the
linux kernel (with printk instead of printf) and I'd prefer it to be
atomic. Also, I can't make a function debug(char *name, char *fmt, ...)
and call printk() from there, because the linux kernel doesn't have
vprintk().

But I will follow your suggesstion and will do it like follows:

#ifdef DEBUG
int debug = 0;
#define DBG(...) (debug & 1 ? (printk(KERN_DEBUG "%s: ", __func__), \
printk(__VA_ARGS__)) : 0)
#else
#define DBG(...)
#endif

where KERN_DEBUG is a string constant defined in the linux kernel
sources.

urs
 
P

pemo

Couldn't you get rid of the int debug = 0 using this?:

#define DEBUG 1

#ifdef DEBUG
#define DBG(...) (DEBUG ? (printk(KERN_DEBUG "%s: ", __func__), \
printk(__VA_ARGS__)) : 0)
#else
#define DBG(...)
#endif
 
P

pemo

pemo wrote:

Urs said:
This is the first answer in this thread, which seems to understand my
post and solves the problem of inserting the __func__ between the fmt
and __VA_ARGS__ without having the ,) when __VA_ARGS__ is empty.

I wanted to avoid calling printf() twice, because I need this in the
linux kernel (with printk instead of printf) and I'd prefer it to be
atomic. Also, I can't make a function debug(char *name, char *fmt, ...)
and call printk() from there, because the linux kernel doesn't have
vprintk().

But I will follow your suggesstion and will do it like follows:

#ifdef DEBUG
int debug = 0;
#define DBG(...) (debug & 1 ? (printk(KERN_DEBUG "%s: ", __func__), \
printk(__VA_ARGS__)) : 0)
#else
#define DBG(...)
#endif

where KERN_DEBUG is a string constant defined in the linux kernel
sources.


Couldn't you get rid of the int debug = 0 using this?:

#define DEBUG 1

#ifdef DEBUG
#define DBG(...) (DEBUG ? (printk(KERN_DEBUG "%s: ", __func__), \
printk(__VA_ARGS__)) : 0)
#else
#define DBG(...)
#endif
 
U

Urs Thuermann

pemo said:
Couldn't you get rid of the int debug = 0 using this?:

#define DEBUG 1

#ifdef DEBUG
#define DBG(...) (DEBUG ? (printk(KERN_DEBUG "%s: ", __func__), \
printk(__VA_ARGS__)) : 0)
#else
#define DBG(...)
#endif

No, your code doesn't make sense.

In my code, debug is initialized to zero (i.e. no debug output) but
can be set at module load time. There are other debug macros, that
test for debug&2 and debug&4.

urs
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top