Macro Variable Argument List with __FILE__ and __LINE__

J

jake1138

I couldn't find an example of this anywhere so I post it in the hope
that someone finds it useful. I believe this is compiler specific (I'm
using gcc), as C99 defines __VA_ARGS__. Comments are welcome.

This will print the file name and line number followed by a format
string and a variable number of arguments. The key here is that you
MUST have a space between __LINE__ and the last comma, otherwise
__LINE__ gets eaten by the ## if args is empty. It took me awhile to
figure that out.

#define DEBUGLOG(fmt, args...) printf("%s(%d)"fmt , __FILE__ ,
__LINE__ , ## args)

I'm curious, does anyone know if the equivelant can be done using
__VA_ARGS__?
 
M

Michael Mair

jake1138 said:
I couldn't find an example of this anywhere so I post it in the hope
that someone finds it useful. I believe this is compiler specific (I'm
using gcc), as C99 defines __VA_ARGS__. Comments are welcome.

This will print the file name and line number followed by a format
string and a variable number of arguments. The key here is that you
MUST have a space between __LINE__ and the last comma, otherwise
__LINE__ gets eaten by the ## if args is empty. It took me awhile to
figure that out.

#define DEBUGLOG(fmt, args...) printf("%s(%d)"fmt , __FILE__ ,
__LINE__ , ## args)

I'm curious, does anyone know if the equivelant can be done using
__VA_ARGS__?

I do.
Probably you want to know whether it can be done: Yes, it can be done.

If you want to know how:
#define DEBUGLOG(fmt, ...) \
printf("%s(%d)"fmt, __FILE__, __LINE__, __VA_ARGS__)

(untested)


Cheers
Michael
 
C

Chris Torek

jake1138 said:
This [gcc-specific trick] will print the file name and line number
followed by a format string and a variable number of arguments. ...

[formatting broken originally by google, now fixed:]

I do.
Probably you want to know whether it can be done: Yes, it can be done.

If you want to know how:
#define DEBUGLOG(fmt, ...) \
printf("%s(%d)"fmt, __FILE__, __LINE__, __VA_ARGS__)

(untested)

This is not quite equivalent. GCC's special "prefix ##" syntax
means "remove the preceding pp-token if the variable arguments
are missing". Hence, if one writes:

DEBUGLOG("got here\n");

with the gcc version, one gets:

printf("%s(%d)""got here", __FILE__, __LINE);

but the C99 version produces:

printf("%s(%d)""got here", __FILE__, __LINE,);

which is not syntactically valid.

There appears to be no way to achieve the desired effect in C99.
As a workaround, one can write:

#define DEBUGLOG(...) \
(printf("%s(%d)", __FILE__, __LINE), printf(__VA_ARGS__))

In other words, just use two calls. Or instead of calling printf()
directly, call your own function that takes three-or-more arguments:

extern int debuglog(const char *, int, const char *, ...);
#define DEBUGLOG(...) debuglog(__FILE__, __LINE__, __VA_ARGS__)

In either case, __VA_ARGS__ will necessarily expand to at least one
parameter, so that the "remove preceding pp-token" behavior is never
needed.
 
M

Michael Mair

Chris said:
jake1138 said:
This [gcc-specific trick] will print the file name and line number
followed by a format string and a variable number of arguments. ...


[formatting broken originally by google, now fixed:]



Michael Mair said:
I do.
Probably you want to know whether it can be done: Yes, it can be done.

If you want to know how:
#define DEBUGLOG(fmt, ...) \
printf("%s(%d)"fmt, __FILE__, __LINE__, __VA_ARGS__)

(untested)


This is not quite equivalent. GCC's special "prefix ##" syntax
means "remove the preceding pp-token if the variable arguments
are missing". Hence, if one writes:

DEBUGLOG("got here\n");

with the gcc version, one gets:

printf("%s(%d)""got here", __FILE__, __LINE);

but the C99 version produces:

printf("%s(%d)""got here", __FILE__, __LINE,);

which is not syntactically valid.

There appears to be no way to achieve the desired effect in C99.
As a workaround, one can write:

#define DEBUGLOG(...) \
(printf("%s(%d)", __FILE__, __LINE), printf(__VA_ARGS__))

In other words, just use two calls. Or instead of calling printf()
directly, call your own function that takes three-or-more arguments:

extern int debuglog(const char *, int, const char *, ...);
#define DEBUGLOG(...) debuglog(__FILE__, __LINE__, __VA_ARGS__)

In either case, __VA_ARGS__ will necessarily expand to at least one
parameter, so that the "remove preceding pp-token" behavior is never
needed.

Thank you very much!
I never used this gcc extension (-std=cXX -pedantic...), so I was
too quick with my assumptions.


Cheers
Michael
 
S

SM Ryan

# I couldn't find an example of this anywhere so I post it in the hope
# that someone finds it useful. I believe this is compiler specific (I'm
# using gcc), as C99 defines __VA_ARGS__. Comments are welcome.
#
# This will print the file name and line number followed by a format
# string and a variable number of arguments. The key here is that you
# MUST have a space between __LINE__ and the last comma, otherwise
# __LINE__ gets eaten by the ## if args is empty. It took me awhile to
# figure that out.
#
# #define DEBUGLOG(fmt, args...) printf("%s(%d)"fmt , __FILE__ ,
# __LINE__ , ## args)

Alternatively,

debug.h
typedef void (*DebugLogFormat)(char *format,...);
DebugLogFormat debugLogSetup(char *file,int line);
#define DEBUGLOG (debugLogSetup(__FILE__,__LINE__))
debug.c
static char *file; static int line;
static void debugLogFormat(char *format,...) {
printf("[%s:%d] ",file,line);
va_list list; va_start(list,format);
vprintf(format,list);
va_end(list);
}
DebugLogFormat debugLogSetup(char *file0,int line0) {
file = file0; line = line0;
return debugLogFormat;
}
 
D

Dave Thompson

On Mon, 07 Feb 2005 12:05:08 -0000, SM Ryan
Alternatively,

debug.h
typedef void (*DebugLogFormat)(char *format,...);
DebugLogFormat debugLogSetup(char *file,int line);
#define DEBUGLOG (debugLogSetup(__FILE__,__LINE__))
debug.c
static char *file; static int line;
static void debugLogFormat(char *format,...) {
printf("[%s:%d] ",file,line);
va_list list; va_start(list,format);
vprintf(format,list);
va_end(list);
}
DebugLogFormat debugLogSetup(char *file0,int line0) {
file = file0; line = line0;
return debugLogFormat;
}

Not safe for threading, which is not in standard C but is in many C
systems and programs. Why not just

..h
typedef int like_printf (const char * /*restrict*/, ...);
like_printf * logPrefix (const char * file, /*unsigned?*/long line);
#define DEBUGLOG logPrefix(__FILE__,__LINE__) /*printfargs*/
..c
like_printf * logPrefix (const char * file, long line)
{ printf ("[%s:%ld] ", file, line); return printf; }
or even
static bool logflag = false;
/* some way to set to true -- or viceversa */
static int dont_printf (const char * /*restrict*/ fmt, ...)
{ return 0; }
like_printf * logPrefix (const char * file, /*ditto*/long line)
{ if( !logflag ) return dont_printf;
/*else*/ /*as before*/ }

Note that this evaluates the log-data arguments even if logging is
disabled by the flag; dont_printf is actually called but discards the
values. This may be costly and generally it is bad style to have
needed sideeffects in statements whose apparent purpose is debugging;
OTOH macro schemes that suppress the evaluation need to be tested in
(only?) the release version, or code-reviewed carefully, or both, to
ensure that they don't have such bugs.

- David.Thompson1 at worldnet.att.net
 

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,999
Messages
2,570,243
Members
46,836
Latest member
login dogas

Latest Threads

Top