Redefine fprintf for debugging purposes

Discussion in 'C Programming' started by Prayag Narula, Jul 23, 2007.

  1. Hi,

    I want to redefine fprintf for debugging purposes. That is I want that
    all the output that is going to the stdout should be logged in a
    file.

    I tried something like


    #define fprintf (x,y,z) my_fprintf(x,y,z)

    and the compiler gave about 100 errors. Can anyone help me with this.
    I have even tried using variadic macros but it seems too complicated.
    Can anyone just help with such a defination.

    Thanks and Regards,
    Prayag Narula
    Prayag Narula, Jul 23, 2007
    #1
    1. Advertising

  2. Prayag Narula

    santosh Guest

    Prayag Narula wrote:

    > Hi,
    >
    > I want to redefine fprintf for debugging purposes. That is I want that
    > all the output that is going to the stdout should be logged in a
    > file.


    <snip>

    You cannot portably redefine Standard library functions and symbols. fprintf
    takes a FILE * argument. Why do you feel that must be stdout. Just pass it
    a FILE * set to a file, presumably opened by fopen.

    FILE *log;
    if((log = fopen("filename", "a")) == NULL) { deal_with_error(); }
    /* ... */
    if(fprintf(log, "format string", ...) < 0) { deal_with_error(); }
    santosh, Jul 23, 2007
    #2
    1. Advertising

  3. Prayag Narula

    Manish Tomar Guest

    On Jul 23, 1:23 pm, Prayag Narula <> wrote:

    > #define fprintf (x,y,z) my_fprintf(x,y,z)
    >

    If there is space between fprintf & (x,y,z) that could be the reason
    for those errors. You need to have it without space "fprintf(x,y,z)".
    Even better would be "#define fprintf my_fprintf" if x y z remain same
    which I think is highly unlikely as u would be changing replacing
    stdout with your file pointer.

    I feel using variadic macros fit better in your scenario as fprintf
    has variable arguments. I would to thank you to introduce me this
    concept as was looking for something like this for a long time.. :)
    Manish Tomar, Jul 23, 2007
    #3
  4. "Prayag Narula" <> wrote in message
    news:...
    > Hi,
    >
    > I want to redefine fprintf for debugging purposes. That is I want that
    > all the output that is going to the stdout should be logged in a
    > file.
    >
    > I tried something like
    >
    >
    > #define fprintf (x,y,z) my_fprintf(x,y,z)
    >
    > and the compiler gave about 100 errors. Can anyone help me with this.
    > I have even tried using variadic macros but it seems too complicated.
    > Can anyone just help with such a defination.
    >

    If all of your printing to stdout is done with:
    fprintf( stdout, ...);
    (that is, using fprintf rather than printf)
    then it is really easy:

    #ifdef DEBUG
    #define OUTFILE myfile
    #else
    #define OUTFILE stdout
    #endif

    Then all print statements become:
    fprintf( OUTFILE, ... );

    Make sure you successfully open myfile before
    any of the fprintf statements are executed.
    --
    Fred L. Kleinschmidt
    Boeing Associate Technical Fellow
    Aero Stability and Controls Computing
    Fred Kleinschmidt, Jul 23, 2007
    #4
  5. >You cannot portably redefine Standard library functions and symbols. fprintf
    >takes a FILE * argument. Why do you feel that must be stdout. Just pass it
    >a FILE * set to a file, presumably opened by fopen.


    I do not want to redefine fprintf portably. Just for debugging
    purposes. Thats why I need to use macros.Actually I am working on an
    embedded device and cannot see the stdout. I want to define a macro
    that redirects output from stdout to a file.

    >fprintf
    >takes a FILE * argument. Why do you feel that must be stdout. Just pass it
    >a FILE * set to a file, presumably opened by fopen.
    >
    >FILE *log;
    > if((log = fopen("filename", "a")) == NULL) { deal_with_error(); }
    > /* ... */
    >if(fprintf(log, "format string", ...) < 0) { deal_with_error(); }


    I cannot keep changing the function call at every call. Thats why a
    macro.

    >If there is space between fprintf & (x,y,z) that could be the reason
    >for those errors. You need to have it without space "fprintf(x,y,z)".
    >Even better would be "#define fprintf my_fprintf" if x y z remain same
    >which I think is highly unlikely as u would be changing replacing
    >stdout with your file pointer


    There is no space between fprintf and (x,y,z). My fault. I did not
    copy paste the codes. :(

    >I feel using variadic macros fit better in your scenario as fprintf
    >has variable arguments.


    I have been fiddling around with variadic macros too. But the thing
    is, the error messages I get are more than just too many or too few
    parameters. For example:

    undefined identifier 'NULL' in config.c
    (this is being returned by fprintf, so something is going on with the
    function that I wote)

    I am not sure if this would be solved using variadic macros. But I
    would try again with a full fledged rewritten fprintf.

    >fprintf( stdout, ...);
    >(that is, using fprintf rather than printf)
    >then it is really easy:
    >
    >#ifdef DEBUG
    >#define OUTFILE myfile
    >#else
    >#define OUTFILE stdout
    >#endif
    >
    >Then all print statements become:
    > fprintf( OUTFILE, ... );


    I do not want to change the code thats already written. But this
    option would be my last resort if nothing else works out.

    Looking forward to more comments.

    Prayag Narula
    Prayag Narula, Jul 24, 2007
    #5
  6. On 24 Jul, 03:48, Prayag Narula <> wrote:

    please leave attributions in

    > >You cannot portably redefine Standard library functions and symbols. fprintf
    > >takes a FILE * argument. Why do you feel that must be stdout. Just pass it
    > >a FILE * set to a file, presumably opened by fopen.

    >
    > I do not want to redefine fprintf portably.


    around here "portably" means "as defined by the C standard". This news
    group
    discusses standard C. So if you don't want to do it portably you're in
    the wrong ng!

    > Just for debugging
    > purposes. Thats why I need to use macros.Actually I am working on an
    > embedded device and cannot see the stdout. I want to define a macro
    > that redirects output from stdout to a file.
    >
    > >fprintf
    > >takes a FILE * argument. Why do you feel that must be stdout. Just pass it
    > >a FILE * set to a file, presumably opened by fopen.

    >
    > >FILE *log;
    > > if((log = fopen("filename", "a")) == NULL) { deal_with_error(); }
    > > /* ... */
    > >if(fprintf(log, "format string", ...) < 0) { deal_with_error(); }

    >
    > I cannot keep changing the function call at every call. Thats why a
    > macro


    why not. With a decent editor that's dead easy. So globally replace
    all

    fprintf (stdout, ...

    with

    fprintf (LOG_STREAM, ...

    then define LOG_STREAM depending where you are. What are you doing in
    non-debug mode? It seems odd to me that your embedded device has files
    but not standard out. Oh wait! is your embedded device a Windows
    machine?
    :)


    <snip>

    --
    Nick Keighley
    Nick Keighley, Jul 24, 2007
    #6
  7. On Jul 24, 5:58 pm, Nick Keighley <>
    wrote:

    >
    > around here "portably" means "as defined by the C standard". This news
    > group
    > discusses standard C. So if you don't want to do it portably you're in
    > the wrong ng!


    Ok ! As they say, "ma bad!" :)

    >
    > why not. With a decent editor that's dead easy. So globally replace
    > all
    >
    > fprintf (stdout, ...
    >
    > with
    >
    > fprintf (LOG_STREAM, ...
    >



    I still do not thing that its such a good idea. I have a feeling it is
    bound to create more problems than it would solve.

    > then define LOG_STREAM depending where you are. What are you doing in
    > non-debug mode? It seems odd to me that your embedded device has files
    > but not standard out.


    In non-debug mode, fprintf is being called with upto 5 parameters. It
    does everything from creating html and js files to printing out error
    messages. I am interested in these error messages that go to stdout.

    >Oh wait! is your embedded device a Windows
    > machine?
    > :)


    :-D Its a Nokia s60 emulator. It has a pseudo terminal but it seems to
    crash whenever there is a lot of output to stdout. Thats why I am
    trying to log it.

    Regards,
    Prayag Narula
    Prayag Narula, Jul 25, 2007
    #7
  8. So basically, this is what I did.

    <debug.h>
    #ifndef __DEBUG_H__
    #define __DEBUG_H__

    #define fprintf(fp,...) my_fprintf(fp, __VA_ARGS__)

    #endif

    </debug.h>



    <debug.c>


    #include <stdio.h>
    #include<string.h>
    #include <stdarg.h>
    #include "debug.h"

    int my_fprintf(FILE *fo, ...)
    {
    va_list ap;
    va_start(ap,fo);
    FILE *fp;
    char *buffer;
    buffer = va_arg(ap,char*);
    fp = fopen("log","a");

    //printf("%s %d",buffer,strlen(buffer));

    if(fo == stdout || fo == stderr)
    {
    fp = fopen("log","a");
    if (fp == NULL)
    return(-1);
    if(fwrite(buffer,sizeof(char),strlen(buffer),fp)> 0)
    return(strlen(buffer));
    }
    else
    {
    return (-1);
    }
    }


    </debug.c>

    Works in gcc but doesn't work in the embedded IDE. I guess, the
    embedded compiler does not support variable arguments macro. Though it
    definitely supports variable argument functions.

    Though I am still testing.

    Anyways, another option that I can think of is

    #define fprintf(x,y) my_fprintf_1(x,y)
    #define fprintf(x,y,z) my_fprintf_2(x,y,z)
    ....
    and so on. A dirty way of doing this. What do you guys think ?



    On Jul 24, 10:59 pm, Prayag Narula <> wrote:
    > On Jul 24, 5:58 pm, Nick Keighley <>
    > wrote:
    >
    >
    >
    > > around here "portably" means "as defined by the C standard". This news
    > > group
    > > discusses standard C. So if you don't want to do it portably you're in
    > > the wrong ng!

    >
    > Ok ! As they say, "ma bad!" :)
    >
    >
    >
    > > why not. With a decent editor that's dead easy. So globally replace
    > > all

    >
    > > fprintf (stdout, ...

    >
    > > with

    >
    > > fprintf (LOG_STREAM, ...

    >
    > I still do not thing that its such a good idea. I have a feeling it is
    > bound to create more problems than it would solve.
    >
    > > then define LOG_STREAM depending where you are. What are you doing in
    > > non-debug mode? It seems odd to me that your embedded device has files
    > > but not standard out.

    >
    > In non-debug mode, fprintf is being called with upto 5 parameters. It
    > does everything from creating html and js files to printing out error
    > messages. I am interested in these error messages that go to stdout.
    >
    > >Oh wait! is your embedded device a Windows
    > > machine?
    > > :)

    >
    > :-D Its a Nokia s60 emulator. It has a pseudo terminal but it seems to
    > crash whenever there is a lot of output to stdout. Thats why I am
    > trying to log it.
    >
    > Regards,
    > Prayag Narula
    Prayag Narula, Jul 25, 2007
    #8
  9. So basically, this is what I did.

    <debug.h>
    #ifndef __DEBUG_H__
    #define __DEBUG_H__

    #define fprintf(fp,...) my_fprintf(fp, __VA_ARGS__)

    #endif

    </debug.h>



    <debug.c>


    #include <stdio.h>
    #include<string.h>
    #include <stdarg.h>
    #include "debug.h"

    int my_fprintf(FILE *fo, ...)
    {
    va_list ap;
    va_start(ap,fo);
    FILE *fp;
    char *buffer;
    buffer = va_arg(ap,char*);
    fp = fopen("log","a");

    //printf("%s %d",buffer,strlen(buffer));

    if(fo == stdout || fo == stderr)
    {
    fp = fopen("log","a");
    if (fp == NULL)
    return(-1);
    if(fwrite(buffer,sizeof(char),strlen(buffer),fp)> 0)
    return(strlen(buffer));
    }
    else
    {
    return (-1);
    }
    }


    </debug.c>

    Works in gcc but doesn't work in the embedded IDE. I guess, the
    embedded compiler does not support variable arguments macro. Though it
    definitely supports variable argument functions.

    Though I am still testing.

    Anyways, another option that I can think of is

    #define fprintf(x,y) my_fprintf_1(x,y)
    #define fprintf(x,y,z) my_fprintf_2(x,y,z)
    ....
    and so on. A dirty way of doing this. What do you guys think ?



    On Jul 24, 10:59 pm, Prayag Narula <> wrote:
    > On Jul 24, 5:58 pm, Nick Keighley <>
    > wrote:
    >
    >
    >
    > > around here "portably" means "as defined by the C standard". This news
    > > group
    > > discusses standard C. So if you don't want to do it portably you're in
    > > the wrong ng!

    >
    > Ok ! As they say, "ma bad!" :)
    >
    >
    >
    > > why not. With a decent editor that's dead easy. So globally replace
    > > all

    >
    > > fprintf (stdout, ...

    >
    > > with

    >
    > > fprintf (LOG_STREAM, ...

    >
    > I still do not thing that its such a good idea. I have a feeling it is
    > bound to create more problems than it would solve.
    >
    > > then define LOG_STREAM depending where you are. What are you doing in
    > > non-debug mode? It seems odd to me that your embedded device has files
    > > but not standard out.

    >
    > In non-debug mode, fprintf is being called with upto 5 parameters. It
    > does everything from creating html and js files to printing out error
    > messages. I am interested in these error messages that go to stdout.
    >
    > >Oh wait! is your embedded device a Windows
    > > machine?
    > > :)

    >
    > :-D Its a Nokia s60 emulator. It has a pseudo terminal but it seems to
    > crash whenever there is a lot of output to stdout. Thats why I am
    > trying to log it.
    >
    > Regards,
    > Prayag Narula
    Prayag Narula, Jul 25, 2007
    #9
  10. Prayag Narula

    Mark Bluemel Guest

    Prayag Narula wrote:
    > On Jul 24, 5:58 pm, Nick Keighley <>
    > wrote:


    >>... With a decent editor that's dead easy. So globally replace
    >>all
    >>
    >> fprintf (stdout, ...
    >>
    >>with
    >>
    >> fprintf (LOG_STREAM, ...
    >>

    [Replace something Prayag snipped

    >> then define LOG_STREAM depending where you are

    >
    > I still do not thing that its such a good idea. I have a feeling it is
    > bound to create more problems than it would solve.


    It's a fairly obvious solution to your problem. What problems do you
    foresee?
    Mark Bluemel, Jul 25, 2007
    #10
  11. Prayag Narula

    Guest

    On Jul 23, 10:23 am, Prayag Narula <> wrote:
    > Hi,


    > all the output that is going to the stdout should be logged in a
    > file.

    /* .... */
    fclose(stdout);
    stdout = fopen("....", "w+");
    /* ... error checking ... */

    What about something like this ?
    , Jul 25, 2007
    #11
  12. Prayag Narula <> writes:

    > So basically, this is what I did.
    >
    > <debug.h>
    > #ifndef __DEBUG_H__
    > #define __DEBUG_H__


    You are liable to run into name problems. Implementations are allowed
    to define __DEBUG_H__ at their leisure. I think the usual "best
    practice" is to use H_DEBUG.

    >
    > #define fprintf(fp,...) my_fprintf(fp, __VA_ARGS__)
    >
    > #endif
    >
    > </debug.h>
    >
    >
    >
    > <debug.c>
    >
    >
    > #include <stdio.h>
    > #include<string.h>
    > #include <stdarg.h>
    > #include "debug.h"
    >
    > int my_fprintf(FILE *fo, ...)
    > {
    > va_list ap;
    > va_start(ap,fo);
    > FILE *fp;
    > char *buffer;
    > buffer = va_arg(ap,char*);
    > fp = fopen("log","a");
    >
    > //printf("%s %d",buffer,strlen(buffer));
    >
    > if(fo == stdout || fo == stderr)
    > {
    > fp = fopen("log","a");
    > if (fp == NULL)
    > return(-1);
    > if(fwrite(buffer,sizeof(char),strlen(buffer),fp)> 0)


    I don't see the value of using variable argument lists if you just
    print the format string (i.e. one argument).

    IMO your best bet is to:

    (1) re-write all the debugging call to make them call a new function
    of your own with no FILE *. It will be a pain the first time, but you
    will have freed yourself from having rather inflexible fprintfs all
    over the place.

    (2) write this debug function to use vfprintf either to stdout,
    stderr, a log file or all (or none) of them under the control of some
    other variables. (These can be global, or you can pass a pointer to a
    debug state structure if you are worried about that.)

    You will avoid the need for variable argument macros this way, too.

    --
    Ben.
    Ben Bacarisse, Jul 25, 2007
    #12
  13. Prayag Narula

    Mark Bluemel Guest

    wrote:
    > On Jul 23, 10:23 am, Prayag Narula <> wrote:
    >
    >>Hi,

    >
    >
    >>all the output that is going to the stdout should be logged in a
    >>file.

    >
    > /* .... */
    > fclose(stdout);
    > stdout = fopen("....", "w+");
    > /* ... error checking ... */
    >
    > What about something like this ?


    Nope - stdout may not be an lvalue...

    freopen() may be appropriate, I guess.
    Mark Bluemel, Jul 25, 2007
    #13
  14. Mark Bluemel <> writes:
    > wrote:
    >> On Jul 23, 10:23 am, Prayag Narula <> wrote:
    >>
    >>>Hi,

    >>
    >>>all the output that is going to the stdout should be logged in a
    >>>file.

    >> /* .... */
    >> fclose(stdout);
    >> stdout = fopen("....", "w+");
    >> /* ... error checking ... */
    >> What about something like this ?

    >
    > Nope - stdout may not be an lvalue...


    Meaning that stdout isn't necessarily an lvalue. (A reasonable, but
    incorrect, parsing of your statement is that stdout is not allowed to
    be an lvalue.)

    And even if stdout happens to be an lvalue, assigning a value to it
    may not necessarily work.

    > freopen() may be appropriate, I guess.


    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jul 26, 2007
    #14
  15. On Jul 25, 9:53 pm, Mark Bluemel <> wrote:
    > wrote:
    > > On Jul 23, 10:23 am, Prayag Narula <> wrote:

    >
    > >>Hi,

    >
    > >>all the output that is going to the stdout should be logged in a
    > >>file.

    >
    > > /* .... */
    > > fclose(stdout);
    > > stdout = fopen("....", "w+");
    > > /* ... error checking ... */

    >
    > > What about something like this ?

    >
    > Nope - stdout may not be an lvalue...
    >
    > freopen() may be appropriate, I guess.


    Works!! Thanks a lot!!
    Prayag Narula, Jul 31, 2007
    #15
  16. Prayag Narula

    Manish Tomar Guest

    >
    > #define fprintf(x,y) my_fprintf_1(x,y)
    > #define fprintf(x,y,z) my_fprintf_2(x,y,z)
    > ...


    I dont think this works... I tried in gcc and it gave redefinition
    error..
    Manish Tomar, Aug 5, 2007
    #16
  17. On Wed, 25 Jul 2007 01:44:14 -0700, Prayag Narula
    <> wrote:

    > #define fprintf(fp,...) my_fprintf(fp, __VA_ARGS__)


    > int my_fprintf(FILE *fo, ...)
    > {
    > va_list ap;
    > va_start(ap,fo);


    Minor: va_start() counts as code, and having code before declarations
    within a block is not standard in C90, although it is supported as an
    extension in several popular compilers and is standard in C99.

    > FILE *fp;
    > char *buffer;
    > buffer = va_arg(ap,char*);
    > fp = fopen("log","a");
    >
    > //printf("%s %d",buffer,strlen(buffer));
    >
    > if(fo == stdout || fo == stderr)
    > {
    > fp = fopen("log","a");
    > if (fp == NULL)
    > return(-1);
    > if(fwrite(buffer,sizeof(char),strlen(buffer),fp)> 0)
    > return(strlen(buffer));


    This will only print the format string, not any converted data that it
    calls for, which means the only valid invocations are with exactly two
    arguments (fp and str) and you don't need variadic. If you really want
    fprintf functionality, use vfprintf, or sprintf or better snprintf
    (also a common extension in C90, standard in C99) plus fwrite.

    > }
    > else
    > {
    > return (-1);


    From your description elsethread I thought you do want to
    allow/support output to files other than stdout/err, you just don't
    want the redirection to apply to those other files.

    > Works in gcc but doesn't work in the embedded IDE. I guess, the
    > embedded compiler does not support variable arguments macro. Though it
    > definitely supports variable argument functions.
    >

    vararg functions have been standard since C90, which is almost
    universally implemented (modulo bugs), and were fairly common even
    before standardization. variadic macros are new in C99, not yet widely
    implemented, and were/are not common outside of C99 and gcc.

    > Though I am still testing.
    >
    > Anyways, another option that I can think of is
    >
    > #define fprintf(x,y) my_fprintf_1(x,y)
    > #define fprintf(x,y,z) my_fprintf_2(x,y,z)
    > ...
    > and so on. A dirty way of doing this. What do you guys think ?
    >

    That can't work at all; Cpp allows only one definition for a macro.

    What does work is
    #define fprintf0(f,s), my_fprintf_0(f,s)
    #define fprintf1(f,s,a) my_fprintf_1(f,s,a)
    #define fprintf2(f,s,a,b) my_fprintf_2(f,s,a,b)
    (where I count the number of variable/data args only) but this
    requires changing each invocation, which you wanted to avoid.

    Using an 'object-like' (nonparameterized) macro instead can work:

    #undef fprintf
    #define fprintf my_fprintf

    void my_fprintf (FILE * f, /*restrict*/ const char * s, ...)
    /* note signature EXACTLY SAME as real fprintf() */
    { blah blah blah }

    and then usage as fprintf (fp, "foo", x, y, z) just expands to
    my_fprintf (fp, "foo", x, y, z) and your function can do its thing.

    Caveat: this is officially not supported by the standard -- overriding
    any standard-library feature is not -- but it is likely to work on all
    real implementations, at least as long as you do it only for source
    i.e. NOT before #include'ing system or even third-party headers. And
    of course it only applies to calls within code you write or modify and
    compile, not within any object libraries that you call.

    - formerly david.thompson1 || achar(64) || worldnet.att.net
    David Thompson, Aug 26, 2007
    #17
    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. Ken McAndrew

    Validators at cross purposes?

    Ken McAndrew, Jan 5, 2004, in forum: ASP .Net
    Replies:
    2
    Views:
    387
    Ken McAndrew
    Jan 6, 2004
  2. Edwin Knoppert
    Replies:
    3
    Views:
    365
    Edwin Knoppert
    Jan 27, 2006
  3. =?Utf-8?B?ZGF2ZS5kb2xhbg==?=

    Tree View for Non-Navigational Purposes

    =?Utf-8?B?ZGF2ZS5kb2xhbg==?=, Mar 19, 2006, in forum: ASP .Net
    Replies:
    2
    Views:
    3,201
    =?Utf-8?B?ZGF2ZS5kb2xhbg==?=
    Mar 20, 2006
  4. =?Utf-8?B?RGFiYmxlcg==?=

    use same DetailsView for multiple purposes?

    =?Utf-8?B?RGFiYmxlcg==?=, Mar 28, 2006, in forum: ASP .Net
    Replies:
    2
    Views:
    4,090
    =?Utf-8?B?RGFiYmxlcg==?=
    Mar 29, 2006
  5. dmtr
    Replies:
    3
    Views:
    2,603
Loading...

Share This Page