【发布时间】:2019-05-27 13:16:19
【问题描述】:
在 Linux(Raspberry Pi 上的 Raspbian)上,我希望我的 C 应用程序使用 printf 打印的任何内容都会在回调中发回给我。
(不,我不是在谈论使用 > some_file.txt 的 shell 重定向。我说的是 C 程序自行决定发送 stdout(因此是 printf ) 到同一程序内的回调。)
(是的,我真的很想这样做。我正在使用 OpenGL 制作一个全屏程序,并希望使用我自己的渲染代码在该程序中向用户呈现任何 printf'd 文本。替换所有printf 调用其他东西都是不可行的。)
我觉得这应该很容易。 StackOverflow 上已经有这个问题的变体,但我找不到完全相同的。
我可以使用fopencookie 来获取FILE*,它最终会调用我的回调。到目前为止,一切都很好。挑战是让stdout 和printf 去那里。
我不能使用freopen,因为它需要一个字符串路径。我要重定向到的FILE* 不是文件系统上的文件,而只是在运行时存在。
我不能使用dup2,因为来自fopencookie 的FILE* 没有文件描述符(fileno 返回-1)。
glibc documentation 表明我可以简单地将 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;
}
【问题讨论】:
-
听起来像是 glibc printf 扩展的问题。您是否考虑过只使用
#define printf cookie_printf或类似的东西。编写自己的函数非常容易,它与printf具有相同的签名,然后调用vfprintf。 stackoverflow.com/a/1737675/1028434
标签: c printf raspbian glibc stdio