有时我们用这种方法在代码中放置一些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
调用,而不是全局关闭缓冲。 最好不要写崩溃的代码…