9

I am calling a function funcB from funcA. funcB uses several printf statements to output data. Is there a way for me to capture that data via funcA? I can not modify funcB.

funcB(){
     printf( "%s", "My Name is" );
     printf( "%s", "I like ice cream" );
}

funcA(){
    funcB();
}
Seth Johnson
  • 14,762
  • 6
  • 59
  • 85
Gene
  • 661
  • 4
  • 10
  • 21
  • 3
    What if `funcB` wouldn't print its output, but return it to `funcA` instead? Hard to say from abstract description as you provided, be more specific. – LihO Jun 19 '12 at 22:19
  • 2
    *"This is a C++ question"* - it looks more like a C question to me. If it were C++ you could do something like: [this](http://stackoverflow.com/a/8076948/168175). – Flexo Jun 19 '12 at 22:23
  • It looks more like an OS-specfic question to me, as alluded to in my answer. – Cheers and hth. - Alf Jun 19 '12 at 22:25

4 Answers4

15

(This answer is a corrected version based on this answer.)

This answer is POSIX centric. Use open to create a file descriptor for the file you want to redirect to. Then, use dup2 to STDOUT_FILENO to change stdout to write to the file instead. But, you'll want to dup the STDOUT_FILENO before you do that, so you can restore stdout with another dup2.

fflush(stdout);
int stdout_fd = dup(STDOUT_FILENO);
int redir_fd = open(redirected_filename, O_WRONLY);
dup2(redir_fd, STDOUT_FILENO);
close(redir_fd);
funcB();
fflush(stdout);
dup2(stdout_fd, STDOUT_FILENO);
close(stdout_fd);

If funcB is using std::cout, use std::cout.flush() instead of fflush(stdout).

If you want to manipulate C++ streams more directly, you can use Johnathan Wakely's answer.

jxh
  • 69,070
  • 8
  • 110
  • 193
  • How to revert stdout once again to the screen? – Viesturs Aug 20 '18 at 14:27
  • 1
    I appended `cout << "should go" < – Viesturs Aug 20 '18 at 14:50
  • @Viesturs You might need to adjust line flushing discipline, but the output should exist if you manually flush it. If not, I expect the code you are testing messed something up. – jxh Aug 20 '18 at 16:09
  • How to do the line flushing? – Viesturs Aug 20 '18 at 20:17
  • `fflush(stdout)` and `cout.flush()`. – jxh Aug 20 '18 at 20:48
  • That didn't help – Viesturs Aug 20 '18 at 21:17
  • @Viesturs: Like I said, I expect the code you are testing messed something up. Consider posting a new question. – jxh Aug 20 '18 at 21:25
  • I am banned to ask questions here. – Viesturs Aug 21 '18 at 13:43
  • @jxh: I'm having the same trouble @Viesturs was. Despite using proper flushing, `stdout` is not restored for me, and printing to it doesn't go to the console or the redirected file. gcc 8.3.0 (or 6.5.0) and glibc 2.29. As you asked him to do, posted a new question here: (with full code) https://stackoverflow.com/questions/56097917/restoring-stdout-after-redirecting-it-via-freopen – user1902689 May 12 '19 at 09:37
  • 1
    @user1902689: Thanks for that. R.'s answer was very enlightening to me. – jxh May 13 '19 at 20:38
2

If nothing else in your program uses printf, you can write your own version and link it explicitly. The linker will not look in the standard library if the function is already defined. You can probably use vsprintf for the implementation, or some safer version with overrun checking if it is supplied by your compiler.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
1

If you're willing to play a dirty game interposing on printf you can 'steal' its output doing something like:

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

static char buffer[1024];
static char *next = buffer;

static void funcB(){
     printf( "%s", "My Name is" );
     printf( "%s", "I like ice cream" );
}

static void funcA(){
    funcB();
    // Do stuff iwth buffer here
    fprintf(stderr, "stole: %s\n", buffer);
    next=buffer; // reset for later.
}

int main() {
  funcA();
}


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;
}

You could use a flag to indicate how to handle the instances where you want printf to work as normal. (E.g. map it onto fprintf or use dlsym()/similar to find the real call).

You could also use realloc to manage the size of the buffer more sensibly.

Flexo
  • 87,323
  • 22
  • 191
  • 272
0

Put funcB in a separate program. You can then capture its standard output, e.g. by piping or by redirecting it to a file. How to do that generally depends on the OS and is outside the realm of C++.

Alternatively, maybe you can redirect your funcA process' standard output to a file, then call FuncB, and retrieve the output from the file.

Again, how to do that is outside the realm of C++ and depends on the OS.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331