禁用stdout和stderr缓冲是否安全?

有时我们用这种方法在代码中放置一些debugging打印件

printf("successfully reached at debug-point 1\n"); some code is here printf("successfully reached at debug-point 2"); Here segmantaion fault occur due to some reason 

现在在这种情况下,只有debug-point1将打印在stdiodebugging点2打印被写入stdio缓冲区,但它不刷新,因为它没有得到\n所以我们认为崩溃发生在debugging点1

如果我用这种方式禁用stdio和stderrstream的缓冲选项,从这里来

 setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); 

那么这是安全的做到这一点?

为什么所有的stream都默认行缓冲?

编辑:

Usualy对于任何文件stream,默认分配的缓冲区的大小是多less? 我认为它的OS依赖。 我想知道关于Linux?

为什么所有的流都是默认行缓冲

由于性能原因,它们被缓冲。 图书馆努力避免进行系统调用,因为它需要很长时间。 并不是所有的都默认缓冲。 例如stderr 通常是无缓冲的, stdout只有在引用tty时才被行缓冲。

那么这是安全的做到这一点?

禁用缓冲是安全的,但我必须说这不是最好的调试技术。

一个可能的方法可能是有一个bool dodebug全局标志,并定义一个宏,如

 #ifdef NDEBUG #define debugprintf(Fmt,...) do{} while(0) #else #define debugprintf(Fmt,...) do {if (dodebug) { \ printf("%s:%d " Fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ fflush(stdout); }} while(0) #endif 

然后在你的代码里面,有一些

 debugprintf("here i=%d", i); 

当然,你可以在上面的宏中做fprintf来代替…注意fflush和附加的换行符的格式。

出于性能原因,应该避免禁用缓冲。

呃,好吧。 你错了。 正是由于这个原因, stderr默认没有被缓存。

编辑:此外,作为一般建议,请尝试使用调试器断点,而不是printf s。 让生活变得更轻松。

某种意义上来说是“安全的”,而另一种则是不安全的。 添加debug printfs是不安全的,出于同样的原因,添加代码来修改stdio缓冲是不安全的,因为这是一个维护的噩梦。 你在做什么不是一个好的调试技术。 如果你的程序得到了段错误,你应该简单地检查核心转储,看看发生了什么。 如果这样做不够,请在调试器中运行该程序,然后逐步执行该操作。 这听起来很难,但它确实非常简单,而且是一项重要的技能。 这是一个示例:

 $ gcc -o segfault -g segfault.c#用-g编译得到调试符号
 $ ulimit -c unlimited#允许写入核心转储
 $ ./segfault#运行程序
分割故障(核心转储)
 $ gdb -q segfault /cores/core.3632#在linux上,核心转储将存在于
                                     #无论目录是最新的
                                     #进程在崩溃的时候。 平时
                                     #这是您运行的目录
                                     # 该程序。
阅读共享库的符号..完成
阅读共享库的符号。  DONE
阅读共享库的符号..完成
 main()在segfault.c:5中的#0 0x0000000100000f3c
 5返回* x;  < - 哦,我的段落发生在5号线
 (gdb)print x <---这是因为程序解除引用
 $ 1 =(int *)0x0 ...一个空指针。

如果你的程序写很多的输出,禁用缓冲可能会使其慢10到1000倍之间。 这通常是不可取的。 如果你的目标只是调试时输出的一致性,那么尝试在你希望输出刷新的地方添加显式fflush调用,而不是全局关闭缓冲。 最好不要写崩溃的代码…