В Linux (Raspbian на Raspberry Pi) я хотел бы сделать так, чтобы все, что мое приложение C печатало с использованием printf
, отправлялось мне обратно в обратном вызове.
(Нет, яя не говорю о перенаправлении оболочки с > some_file.txt
. Я говорю о программе на C, которая сама принимает решение отправить stdout
(и, следовательно, printf
) обратному вызову в той же программе.)
(Да, я действительно хочу это сделать. Я делаю полноэкранную программу с использованием OpenGL и хочу представить любой текст printf
пользователю в этой программе, используя мой собственный рендеринг.код. Замена всех вызовов printf
чем-то другим не представляется возможным.)
Я чувствую, что это должно быть легко.В StackOverflow уже есть варианты этого вопроса, но ни один из них, которые я смог найти, не изменился.
Я могу использовать fopencookie
, чтобы получить FILE*
, который в конечном итоге вызывает мой обратный вызов.Все идет нормально.Задача состоит в том, чтобы заставить stdout
и printf
идти туда.
I не может использовать freopen
, потому что он принимает путь строки.FILE*
Я хочу перенаправить не файл в файловой системе, а просто существует во время выполнения.
I не может использовать dup2
, потому что FILE*
from fopencookie
не имеет дескриптора файла (fileno
возвращает -1).
Документация glibc предполагает, что я могу просто переназначить stdout
на мою новую FILE*
: "stdin, stdout и stderr - это обычные переменные, которые вы можете установить, как и любые другие." .Это почти работает .Все, что напечатано с fprintf (stdout, "whatever")
, действительно отправляется на мой обратный вызов, также как и любое printf
, которое имеет любые спецификаторы формата.Тем не менее, любой вызов printf
со строкой без спецификаторов формата все равно переходит к «исходному» стандартному выводу.
Как мне добиться того, что я пытаюсь сделать?
PS: меня не волнует мобильность.Это будет работать только в моей текущей среде.
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <stdarg.h>
#include <alloca.h>
#include <string.h>
static ssize_t my_write_func (void * cookie, const char * buf, size_t size)
{
fprintf (stderr, "my_write_func received %d bytes\n", size);
char * copy = (char*) alloca (size + 1);
assert (copy);
copy[size] = 0;
strncpy (copy, buf, size);
fprintf (stderr, "Text is: \"%s\"\n", copy);
fflush (stderr);
return size;
}
static FILE * create_opencookie ()
{
cookie_io_functions_t funcs;
memset (&funcs, 0, sizeof (funcs));
funcs.write = my_write_func;
FILE * f = fopencookie (NULL, "w", funcs);
assert (f);
return f;
}
int main (int argc, char ** argv)
{
FILE * f = create_opencookie ();
fclose (stdout);
stdout = f;
// These two DO go to my callback:
fprintf (stdout, "This is a long string, fprintf'd to stdout\n");
printf ("Hello world, this is a printf with a digit: %d\n", 123);
// This does not go to my callback.
// If I omit the fclose above then it gets printed to the console.
printf ("Hello world, this is plain printf.\n");
fflush (NULL);
return 0;
}