pet*_*rpi 3 c printf glibc stdio raspbian
在Linux上(Raspberry Pi上的Raspbian)我想这样做,以便我的C应用程序打印使用的任何内容都会printf在回调中发回给我.
(不,我不是在谈论shell重定向> some_file.txt.我正在谈论一个C程序自己决定发送stdout(因此printf)在同一个程序中的回调.)
(是的,我确实想要这样做.我正在使用OpenGL制作全屏程序,并希望printf使用我自己的渲染代码在该程序中向用户呈现任何文本.printf用其他东西替换所有调用是不可行.)
我觉得这应该很容易.StackOverflow上已经存在这个问题的变体,但我找不到的都是完全一样的.
我可以fopencookie用来获得一个FILE*最终调用我的回调.到现在为止还挺好.挑战是去stdout和printf去那里.
我无法使用,freopen因为它需要一个字符串路径.在FILE*我想重定向到是不是文件系统中的文件,而只是在运行时存在.
我无法使用,dup2因为FILE*from fopencookie没有文件描述符(fileno返回-1).
在glibc的文件表明,我可以简单地重新分配stdout给我的新FILE*:"标准输入,标准输出,和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;
}
Run Code Online (Sandbox Code Playgroud)
这似乎是GLIBC中的一个错误.
与之printf("simple string")不同的原因printf("foo %d", 123)是GCC将前者转换为a puts,并认为它们是等价的.
据我所知,它们应该是等价的.这个手册页说明了puts输出stdout,就像printf那样.
但是,在GLIBC printf输出到stdout 这里,但puts输出到_IO_stdout 这里,这些并不相同.这已被报告为glibc错误 (上游错误).
要解决此错误,您可以使用-fno-builtin-printf标志进行构建.这可以防止GCC转换printf成puts我的系统产生:
$ ./a.out
my_write_func received 126 bytes
Text is: "This is a long string, fprintf'd to stdout
Hello world, this is a printf with a digit: 123
Hello world, this is plain printf.
"
Run Code Online (Sandbox Code Playgroud)
这种解决方法当然是不完整的:如果你puts直接调用,或链接调用printf("simple string")和未编译的对象文件-fno-builtin-printf(可能来自第三方库),那么你仍然会遇到问题.
不幸的是你无法分配_IO_stdout(这是一个宏).你可以做的唯一的另一件事(我能想到的)是你自己的链接puts,它只是返回printf("%s", arg).如果您要链接libc.so.6,这应该有效,但如果您链接,可能会造成麻烦libc.a.
| 归档时间: |
|
| 查看次数: |
162 次 |
| 最近记录: |