Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Macro Variable Argument List with __FILE__ and __LINE__

Reply
Thread Tools

Macro Variable Argument List with __FILE__ and __LINE__

 
 
jake1138
Guest
Posts: n/a
 
      02-04-2005
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__?

 
Reply With Quote
 
 
 
 
Michael Mair
Guest
Posts: n/a
 
      02-04-2005
jake1138 wrote:
> 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
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
 
Reply With Quote
 
 
 
 
Chris Torek
Guest
Posts: n/a
 
      02-04-2005
>jake1138 wrote:
>> 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:]

>> #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__?


In article <(E-Mail Removed)>
Michael Mair <(E-Mail Removed)> wrote:
>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.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
 
Reply With Quote
 
Michael Mair
Guest
Posts: n/a
 
      02-05-2005
Chris Torek wrote:
>>jake1138 wrote:
>>
>>>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:]
>
>
>>>#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__?

>
>
> In article <(E-Mail Removed)>
> Michael Mair <(E-Mail Removed)> wrote:
>
>>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
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
 
Reply With Quote
 
SM Ryan
Guest
Posts: n/a
 
      02-07-2005
"jake1138" <(E-Mail Removed)> wrote:
# 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;
}

--
SM Ryan http://www.rawbw.com/~wyrmwif/
A bunch of savages in this town.
 
Reply With Quote
 
Dave Thompson
Guest
Posts: n/a
 
      02-14-2005
On Mon, 07 Feb 2005 12:05:08 -0000, SM Ryan
<(E-Mail Removed)> wrote:
<snip>
> 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
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Python equivt of __FILE__ and __LINE__ Bill Davy Python 14 02-14-2008 08:11 AM
__FILE__ and __LINE__ Neo C++ 5 11-29-2006 06:52 PM
__LINE__ and __FILE__ functionality in Python? Joakim Hove Python 4 08-13-2006 01:17 PM
__FILE__ and __LINE__ within macros Kenneth Brody C Programming 7 04-05-2006 08:30 PM
Macro for memory logging using __FILE__ and __LINE__ Spry C Programming 1 07-26-2003 01:13 PM



Advertisments