function pointer WITH variable length argument list

Discussion in 'C Programming' started by Keve Nagy, Apr 4, 2009.

  1. Keve Nagy

    Keve Nagy Guest

    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
    Keve Nagy, Apr 4, 2009
    #1
    1. Advertising

  2. Keve Nagy

    Eric Sosman Guest

    Keve Nagy wrote:
    > [...]
    > 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/>.

    --
    Eric Sosman
    lid
    Eric Sosman, Apr 4, 2009
    #2
    1. Advertising

  3. Keve Nagy

    Guest

    On 4 Apr, 13:48, Eric Sosman <> wrote:
    > Keve Nagy wrote:
    > > [...]
    > >   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>
    , Apr 4, 2009
    #3
  4. Keve Nagy

    luserXtrog Guest

    On Apr 4, 8:37 am, wrote:
    > On 4 Apr, 13:48, Eric Sosman <> wrote:
    >
    >
    >
    > > Keve Nagy wrote:
    > > > [...]
    > > >   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!
    --
    lxt
    luserXtrog, Apr 4, 2009
    #4
  5. Keve Nagy

    Keve Nagy Guest

    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
    Keve Nagy, Apr 4, 2009
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. ANDERS FLODERUS
    Replies:
    1
    Views:
    372
    Rob Williscroft
    Dec 20, 2003
  2. Ben Kial
    Replies:
    1
    Views:
    648
    Eric Enright
    Nov 15, 2004
  3. S?ren Gammelmark
    Replies:
    1
    Views:
    1,884
    Eric Sosman
    Jan 7, 2005
  4. Vijai Kalyan
    Replies:
    4
    Views:
    704
    Vijai Kalyan
    Nov 8, 2005
  5. AikidoGuy
    Replies:
    11
    Views:
    558
    Seebs
    Nov 21, 2011
Loading...

Share This Page