473,322 Members | 1,241 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,322 software developers and data experts.

variadic macros and and empty replacement for __VA_ARGS__

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
Mar 27 '06 #1
15 14075
Urs Thuermann <ur*@isnogud.escape.de> writes:
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__)
<SNIP> 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/comp.lang.c/browse_frm/thread/ac0bda529a91d754/949239c624c9fe71?lnk=st&q=logging+group%3Acomp.lan g.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).

--

John Devereux
Mar 27 '06 #2
On 2006-03-27, John Devereux <jd******@THISdevereux.me.uk> wrote:
Urs Thuermann <ur*@isnogud.escape.de> writes:
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__)

<SNIP>
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/comp.lang.c/browse_frm/thread/ac0bda529a91d754/949239c624c9fe71?lnk=st&q=logging+group%3Acomp.lan g.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.
Mar 27 '06 #3
> 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__) )

Mar 27 '06 #4
John Devereux wrote:
Urs Thuermann <ur*@isnogud.escape.de> writes:
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__)

<SNIP>
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/comp.lang.c/browse_frm/thread/ac0bda529a91d754/949239c624c9fe71?lnk=st&q=logging+group%3Acomp.lan g.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).


See this one too:

http://groups.google.co.uk/group/com...d17634c1ed7065

--
==============
Not a pedant
==============
Mar 27 '06 #5
raxip schrieb:
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__) )


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

-Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Mar 27 '06 #6
Assumptions are wonderous creatures.

Mar 27 '06 #7
raxip wrote:
Assumptions are wonderous creatures.


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

Brian

--
Please quote enough of the previous message for context. To do so from
Google, click "show options" and use the Reply shown in the expanded
header.
Mar 27 '06 #8
> That's nice. What does it have to do with anything? See my .sig below
for valuable information.


Is this better?

Mar 27 '06 #9
raxip wrote:
That's nice. What does it have to do with anything? See my .sig
below for valuable information.


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
Mar 27 '06 #10
Michael Mair wrote:
raxip schrieb:
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__) )


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);
}

Mar 27 '06 #11
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"?
Mar 29 '06 #12
> 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
Mar 31 '06 #13
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

Mar 31 '06 #14
pemo wrote:

Urs Thuermann wrote:
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.

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

Apr 1 '06 #15
"pemo" <us***********@gmail.com> writes:
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
Apr 3 '06 #16

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: jois.de.vivre | last post by:
Hi, I'm writing a C++ program that uses C style macros for debugging purposes. I have code that looks something like this: #define DEBUG(str, ...) Show(__FILE__, __LINE__, str, ##...
4
by: Augustus S.F.X Van Dusen | last post by:
I have recently come across the following construction: #define P_VAR(output, string, args...) \ fprintf (output, "This is "string"\n", ##args) which can be invoked as follows: int x = 1,...
3
by: Trent Buck | last post by:
(Note: C99 supports variadic macros, but C89 does not.) I'm pretty sure what I'm trying to do is impossible, but I'll ask here in case I'm missing something. I'm trying to define generic,...
7
by: Michael B Allen | last post by:
If I define a variadic macro like say: #define PRINT(fmt, ...) _myprintf(__FILE__ ": " fmt, __VA_ARGS__) and I call this like: PRINT("no args"); the preprocessor generates:
3
by: Thomas Carter | last post by:
I understand that C99 supports variadic macros. However, is it not the case that a variadic macro defined as #define SAMPLE_MACRO(...) Bloody-blah must take at least one argument? I would be...
12
by: Laurent Deniau | last post by:
I was playing a bit with the preprocessor of gcc (4.1.1). The following macros expand to: #define A(...) __VA_ARGS__ #define B(x,...) __VA_ARGS__ A() -nothing, *no warning* A(x) -x ...
8
by: Christof Warlich | last post by:
Hi, is there any way to access individual elements in the body of a variadic macro? I only found __VA_ARGS__, which always expands to the complete list. Thanks for any help, Christof
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.