Thread: Redirecting printf

  1. #1
    Registered User
    Join Date
    May 2015
    Posts
    56

    Redirecting printf

    Hello,

    I've modified a program found on the internet for a test. Works fine.
    I have a module with serveral 'C' functions, I would like to capture the printf's from all the functions.
    Do I have to create a new "char* funcA()" for each of the functions or is there someway I could apply the modiified printf to all the functions in the module.

    Regards
    Code:
    #include <stdio.h>
    #include <stdarg.h>
    #include <stdlib.h>
    #include <pwd.h>
    #include <unistd.h>
    
    #include "myPrintF.h"
    
    static char buffer[1024]; // ? size needed
    static char *next = buffer;
    
    const char *getUserName() {
        uid_t uid = geteuid();
        struct passwd *pw = getpwuid(uid);
        if (pw) return pw->pw_name;
        return "";
    }
    
    void funcB() {
        printf ("%s%s%s\n", "The current user name is '", getUserName(), "'.");
        printf ("%s", "I like ice cream!");
    }
    
    char* funcA() {
        funcB();
        // Do stuff with buffer here
        next = buffer; // reset for later.
        return (char *) buffer;
    }
    
    int printf(const char *fmt, ...) {
       va_list argp;
       va_start(argp, fmt);
       const int ret = vsnprintf(next, sizeof buffer - (next - buffer), fmt, argp);
       next += ret;
       va_end(argp);
       return ret;
    }
    Code:
    #ifndef MYPRINTF_H
    #define MYPRINTF_H
    
    #ifdef __cplusplus
    extern "C"
    {
    #endif
    
    char* funcA();
    
    #ifdef __cplusplus
    };
    #endif
    
    #endif // MYPRINTF_H
    Code:
    // callling program
        printf("%s\n", "Returned string:-");
        printf ("%s\n", funcA());

  2. #2
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by mad-hatter View Post
    I would like to capture the printf's from all the functions.
    Do I have to create a new "char* funcA()" for each of the functions or is there someway I could apply the modiified printf to all the functions in the module.
    Eh? Wat?

    You wish to interpose printf(). Instead of having it print to the standard output, you wish to capture it into a buffer. This works, and is done in the example.

    I just do not understand what the "someway I could apply the modiified printf to all the functions in the module" part means.

    If you mean you want to capture the output of each printf(), but in separate buffers so that you can better observe which one printed what, there are two basic approaches.

    If you have source code for the module, it is best to use a preprocessor macro to override printf(), and also avail yourself to the __FILE__, __LINE__, and __FUNCTION__ macros. The first and last expand to strings, the name of the file and the current function, respectively, and the middle one expands to the line number in the current file. For example, you could insert
    Code:
    #define printf(fmt...) my_printf(__FILE__, __LINE__, __FUNCTION__, fmt)
    extern void my_printf(const char *const filename, const long linenum, const char *const functionname, const char *const format, ...);
    at the beginning of each source file (via an include file) when compiling the module, and all the printf() commands would call my_printf() instead, with the file name, line number, and function name of where the printf() call originated in.

    Personally, I tend to just use
    Code:
    #define printf(fmt...) do { \
            fprintf(stdout, "%s:%s():%ld", __FILE__, __FUNCTION__, __LINE__); \
            fprintf(stdout, fmt); \
            fflush(stdout); \
        } while (0)
    instead, which simply adds the file name, function, and line number to the beginning of each print output, and flushes the output immediately.

    If you do not have source code for the module, but you can interpose the printf() function (as your example code already does, so you definitely can do this), you need some help from your compiler. For example, GCC provides __builtin_extract_return_addr( __builtin_return_address(0)) built-in, which evaluates to the address where the current function was called from. You could use that address and the timestamp to classify each print() output, using a singly linked list of outputs,
    Code:
    struct output {
        struct output *next;
        void *callsite;
        struct timespec when;
        size_t size;
        char data[];
    };
    If the module is annoyingly complex, then I'd combine the two above -- to get the caller file name, function name, and line number instead of just callers address --, collect all the print outputs until the end of the program, and finally add a function to output all print outputs as a Dot (Graphviz) graph, with time indicated using arrows, each print output in a separate node, and each function being a subgraph. (See the cluster example; instead of the a0, b0, and so on, you'd have the exact printout in the bubbles instead.)

  3. #3
    Registered User
    Join Date
    May 2015
    Posts
    56
    Hello Nominal Animal,

    Thanks for your reply.

    I should have phrased my question better,
    "someway I could apply the modified printf to all the functions in the module"
    What I should have asked is,
    "someway I could apply the modified printf to all the separate programs in the module".
    i.e. void myProg1(), void myprog2(), void myProg2() etc.
    Your advice will certainly help, I don't particularly want to modify the 'C' source, but maybe its necessary. I will have a play and see how far I get.

    Regards

  4. #4
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by mad-hatter View Post
    "someway I could apply the modified printf to all the separate programs in the module".
    i.e. void myProg1(), void myprog2(), void myProg2() etc.
    I still don't understand what your goal is: those are functions, not "programs", and there is no "module" concept in C, so I have no idea what you might mean by "module". I'm not nitpicking, I honestly do not understand what your intent is.

    Anyway, if you put the preprocessor magic in a header file, say my_debug_printf.h for example,
    Code:
    #ifndef printf
    #define printf(fmt...) my_debug_printf(__FILE__, __FUNCTION__, __LINE__, fmt)
    
    #ifdef __cplusplus
    extern "C"
    {
    #endif
    
    extern int my_debug_printf(const char *const filename, const char *const funcname, const long linenum, const char *const format, ...);
    
    #ifdef __cplusplus
    };
    #endif
    
    #endif /* printf */
    you can just include that header file. GCC in particular allows you to supply -include my_debug_printf.h at the command line when compiling, making it automagically included as if you had added #include "my_debug_printf.h" in the sources. Compile the my_debug_printf() in a separate file, and link it to the final program, and you're done; no need to actually modify any source or header files at all, just recompile with new options and added new files.

    If you want to interpose printf() at run time, that is quite simple to do in Linux, but you have to interpose a number of other functions too, to get the effect you want. In particular, if you use -O2 optimization flag at compile time (which I do, almost habitually), then printf("Hello, world!\n"); gets compiled as if you had written puts("Hello, world!"); . In other words, you need to interpose at least puts() too.

    Recompiling is much better option, because then you get the file and function names and line numbers, to tell you exactly which line printed which output.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Redirecting stdout
    By Soel in forum C Programming
    Replies: 3
    Last Post: 01-30-2011, 03:29 PM
  2. Redirecting I/O
    By suwie in forum C Programming
    Replies: 6
    Last Post: 09-30-2004, 09:53 PM
  3. redirecting stdout
    By gregulator in forum C Programming
    Replies: 2
    Last Post: 04-22-2004, 10:07 AM
  4. redirecting console I/O
    By Slavisa in forum Windows Programming
    Replies: 0
    Last Post: 06-25-2003, 07:40 AM
  5. Redirecting cin?
    By rafe in forum C++ Programming
    Replies: 4
    Last Post: 10-10-2002, 09:28 AM