function pointer WITH variable length argument list

K

Keve Nagy

Hello Everyone,
I am trying to put together my ultimate TraceMessage function, but the
nature of difficulties I experience is beyound my C programming limits,
so I would like to request some community help to broaden that barrier.

I am only a hobby C programmer and I only do this out of curiosity, so
forgive me if I am saying, asking or assuming stupid things here! :)

For reference: This is a CLI tool, built using gcc.

Here is what I am trying to achieve:
Consider the standard printf() function. Throughout my sourcecodes I
use this to send out informative trace messages to standard output.
These messages are extremely useful during the development of the code,
and later again during debugging or enhancement. But their appearance is
not required for the normal operation of the finished program.
What I am looking for is a way to keep these trace-message printf()
lines in the code, but still be able to turn their action on or off at
run-time.
For example, if I start the program with a --debug argument it should
print out the trace messages, but should not display them otherwise.

My greatest difficulty is that I wanted to implement this traceMessage
function as a single call. Just like having the ability to call printf()
with an extra first int argument before the format string, and if that
argument has a value of 1 then the output should be printed or if it has
a value of 0 then no output should be printed.
Examples:
printfTraceMessage(1,"This is a format string with %d arguments.",1);
/* the line above should produce the equivalent of
printf("This is a format string with %d arguments.",1); */

printfTraceMessage(1,"Error %d occured in function %s where variable %s
had the value of %s.", holdingErrorcode, holdingFunctionname,
holdingVarname, var);
/* the line above should produce the equivalent of
printf("Error %d occured in function %s where variable %s had the
value of %s.", holdingErrorcode, holdingFunctionname, holdingVarname,
var); */

printfTraceMessage(0,"This is a format string with %d arguments.",1);
/* the line above should not produce any output, due to the 0 value
of the first argument */


So the extreme flexibility of variable arguments with printf() should
remain, but I need the additional ability to indicate if that printf()
should actually be carried out or should simply be ignored.

The way I currently do this is the following:
1., use sprintf(globalTraceMessageStr, "formatstring" ,x ,y, ...);
2., call my printTraceMsg() function.

void printTraceMsg(void) {
if (globalDebugIndicator==1) printf(globalTraceMessageStr);
}

So all I do is set the value of the global variable
"globalDebugIndicator" to control if I want to see the messages printed
or not.
But this method requires me to use two calls to achieve what I need. One
to sprintf(), and another to printTraceMsg(). So I alway need
double-instruction lines like:
sprintf(globTrcMsgStr, "fmt str", v1, v2, ...); printTraceMsg();

I alway wanted to replace this with a single instruction call, but so
far I was unable to implement that upgrade.

The idea was to use a function pointer, which could either point to
printf() or point to an empty function like:
void doNothing(void) { /* this intentionally does nothing */ };
Handling the extremely flexible variable argument list of printf() is
where I fail to implement this idea.
I also failed to implement another idea, creating a function that gets
an arbitrary printf() call as its only one parameter. Something like:
doWhenDebugIsOn( printf("fmt str",v1,v2,...,vN) );
Again, handling the extremely flexible way printf() processes variable
length arguments is where I fail.

So I believe I should somehow unite the use of a function pointer AND
variable length arguments, but how would I do that. I just wasn't able
to put this together using the stdarg.h samples and examples.

I would appreciate any suggestion on this topic or pointer to related
contents. Alternative ways to achieve my single-instruction-call
tracemessage function are also welcome!

Regards,
Keve
 
E

Eric Sosman

Keve said:
[...]
Consider the standard printf() function. Throughout my sourcecodes I
use this to send out informative trace messages to standard output.
These messages are extremely useful during the development of the code,
and later again during debugging or enhancement. But their appearance is
not required for the normal operation of the finished program.
What I am looking for is a way to keep these trace-message printf()
lines in the code, but still be able to turn their action on or off at
run-time.
[...]

The essential piece you need is the vfprintf() function.
Your own tracing function would look something like

#include <stdio.h>
#include <stdarg.h>
extern int tracing_is_enabled;

void trace(const char *format, ...) {
if (tracing_is_enabled) {
va_list ap;
va_start (ap, format);
vfprintf (stderr, format, ap);
va_end (ap);
}
}

See also Question 15.12 in the comp.lang.c Frequently
Asked Questions (FAQ) list, <http://www.c-faq.com/>.
 
G

Guest

Keve said:
[...]
  Consider the standard printf() function. Throughout my sourcecodes I
use this to send out informative trace messages to standard output.
These messages are extremely useful during the development of the code,
and later again during debugging or enhancement. But their appearance is
not required for the normal operation of the finished program.
What I am looking for is a way to keep these trace-message printf()
lines in the code, but still be able to turn their action on or off at
run-time.
[...]

     The essential piece you need is the vfprintf() function.
Your own tracing function would look something like

        #include <stdio.h>
        #include <stdarg.h>
        extern int tracing_is_enabled;

        void trace(const char *format, ...) {
            if (tracing_is_enabled) {
                va_list ap;
                va_start (ap, format);
                vfprintf (stderr, format, ap);
                va_end (ap);
            }
        }

or

#include <stdio.h>
#include <stdarg.h>

void trace(int tracing_is_enabled, const char *format, ...) {
if (tracing_is_enabled) {
va_list ap;
va_start (ap, format);
vfprintf (stderr, format, ap);
va_end (ap);
}
}

<snip>
 
L

luserXtrog

Keve said:
[...]
  Consider the standard printf() function. Throughout my sourcecodes I
use this to send out informative trace messages to standard output.
These messages are extremely useful during the development of the code,
and later again during debugging or enhancement. But their appearance is
not required for the normal operation of the finished program.
What I am looking for is a way to keep these trace-message printf()
lines in the code, but still be able to turn their action on or off at
run-time.
[...]
     The essential piece you need is the vfprintf() function.
Your own tracing function would look something like
        #include <stdio.h>
        #include <stdarg.h>
        extern int tracing_is_enabled;
        void trace(const char *format, ...) {
            if (tracing_is_enabled) {
                va_list ap;
                va_start (ap, format);
                vfprintf (stderr, format, ap);
                va_end (ap);
            }
        }

or

       #include <stdio.h>
       #include <stdarg.h>

        void trace(int tracing_is_enabled, const char *format, ....) {
            if (tracing_is_enabled) {
                va_list ap;
                va_start (ap, format);
                vfprintf (stderr, format, ap);
                va_end (ap);
            }
        }

<snip>

or with function pointers, as you suspected. But the flag is probably
simpler (and uses fewer global names).

#include <stdio.h>
#include <stdarg.h>

void trace_on( const char *format, ...) {
va_list ap;
va_start (ap, format);
vfprintf (stderr, format, ap);
va_end (ap);
}

void trace_off( const char *format, ...) {
}

void (*trace)( const char *format, ...) = trace_off;


int main(void) {
int tracing_is_enabled = 1;
trace("%s!\n", "yo mama");
/*...*/
if (tracing_is_enabled) {
trace = trace_on;
}
/*...*/
trace("%s!\n", "yo mama");
return 0;
}


I just love function pointers!
 
K

Keve Nagy

Thanks Guys!
For all three of you!

Your suggestion makes my extremely difficult problem an easy everyday
task. I'm ashamed to admit that I didn't know about the existence of the
vprintf() family of functions. Especially ashamed as all one needs to
learn about them is "man 3 printf". It was all right by my nose all
along and I never recognized it.
While I am in such a confession-mood, I am also ashamed to learn that
there is a C-faq I never knew about, and it has an annoyingly obvious
URL of http://www.c-faq.com.

Do you remember that last moment of the movie "Men in Black 2" where
Tommy Lee Jones opens a door for Will Smith, showing him that the world
as he understood so far was no more than a baggage locker of a much
larger world.
Damn, you guys just opened that door to me today!

Best Regards,
Keve
 

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,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top