4ntoine
4ntoine

Reputation: 20420

How to intercept printf() in c++ code?

I'm using static library that produces std output using printf(). How can i intercept it in order to show the output in my app and do some highlighting for example?

I have the sources of the lib and i can modify it slightly if needed.

Upvotes: 1

Views: 2438

Answers (2)

Mike DeSimone
Mike DeSimone

Reputation: 42845

I have the sources of the lib and i can modify it slightly if needed.

Well, if you're really sure they're using printf, and you can build their code, you can use that against them so long as you don't have other places in there that use printf.

(I'm assuming a Unix-like platform, so there might need to be some modification to get this to work elsewhere.)

One thing you can do is redefine printf to point to your own version. Another is to write your own printf and link it in before the standard libraries. Neither of these routes are really what you'd consider recommended practice, though they should work. Neither route requires modification of the source of the library.

Redefining printf

Here we just mess with the compiler's concept of printf by telling it that it's really a different function. Add something like this to your Makefile:

CFLAGS += -Dprintf=redirected_printf
CXXFLAGS += -Dprintf=redirected_printf

(Some build systems use the variable DEFINES for this purpose; YMMV.)

This tells the compiler to replace every instance of the identifier printf with redirected_printf. It's the same as if you put #define printf redirected_printf at the top of every source file.

Now you just need to write the redirected_printf function. I prefer to pass the formatting off to another function in stdio, vasprintf, which does the same thing as printf except it takes a va_list instead of ... and returns a pointer to a heap-allocated string with the output.

#include <stdarg.h>
#include <stdio.h>
extern "C" int redirected_printf(const char * format, ...) {
    // Make formatted string.
    char* outstr = 0;
    va_list ap;
    va_start(ap, format);
    int result = vasprintf(&outstr, format, ap);
    va_end(ap);
    if(result < 0) // Error occurred and `outstr` undefined if result < 0.
        return result;

    // Do something with the string in `outstr` here, like display it in a dialog.

    // Clean up and return.
    free(outstr);
    return result;
}

Replacing printf

This is a bit trickier, because you have to write a function named printf that works like replacement_printf above, and then you have to convince the linker to link to your version instead of the standard library's. You might be able to just stick your printf in one of your compilation units and be done with it; when the clinker links the library you're redirecting to your sources, it will find your printf and link to it; then later when it sees the one in the standard library, it will just drop it because at that point nothing calls it.

If that doesn't work, you can try to put your printf into a library of your own with the ar and ranlib commands, then link that library after the one you're redirecting.

Note that if this library you're trying to redirect is a shared library (like a DLL or .so file), this probably won't work; it was linked to the standard printf back when it was built.

This route has a lot more caveats and depends on just how your linker works and a bunch of other things, so I don't recommend it, but I'm including it here for completeness.

Upvotes: 3

4ntoine
4ntoine

Reputation: 20420

i was able to do it using freopen(..);: http://www.cplusplus.com/reference/cstdio/freopen/

Upvotes: 1

Related Questions