【问题标题】:Is it safe to disable buffering with stdout and stderr?使用 stdout 和 stderr 禁用缓冲是否安全?
【发布时间】:2023-04-08 01:12:01
【问题描述】:

有时我们会以这种方式在代码中添加一些调试打印

printf("successfully reached at debug-point 1\n"); 

some code is here

printf("successfully reached at debug-point 2"); 

在最后一个printf 之后发生分段错误。

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

如果我以这种方式禁用 stdiostderr 流的缓冲选项

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

那么,这样做安全吗?

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

编辑:

通常为任何文件流默认分配的缓冲区大小是多少?我认为它取决于操作系统。我想了解Linux。

【问题讨论】:

    标签: c linux stdout stderr buffering


    【解决方案1】:

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

    出于性能原因,它们被缓冲。该库努力避免进行系统调用,因为它需要很长时间。默认情况下,并非所有这些都被缓冲。例如,stderr通常是无缓冲的,stdout 仅在引用 tty 时才进行行缓冲。

    那么这样做安全吗?

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

    【讨论】:

      【解决方案2】:

      一种可能的方法是使用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 和格式中附加的换行符。

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

      【讨论】:

        【解决方案3】:

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

        $ gcc -o segfault -g segfault.c # 用-g编译得到调试符号 $ ulimit -c unlimited # 允许写入核心转储 $ ./segfault # 运行程序 分段错误(核心转储) $ gdb -q segfault /cores/core.3632 # 在linux上,核心转储将存在于 # 任何当前的目录 # 崩溃时的进程。通常 # 这是你运行的目录 # 该程序。 读取共享库的符号.. 完成 共享库的读取符号。完毕 读取共享库的符号.. 完成 #0 0x0000000100000f3c in main () at segfault.c:5 5 返回 *x;

        【讨论】:

          【解决方案4】:

          嗯,好吧。 你错了。正是因为这个原因,stderr默认是缓冲的。

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

          【讨论】:

            【解决方案5】:

            如果您的程序写入大量输出,禁用缓冲可能会使其慢 10 到 1000 倍。这通常是不可取的。如果您的目标只是调试时输出的一致性,请尝试在您希望输出刷新的位置添加显式 fflush 调用,而不是全局关闭缓冲。而且最好不要写崩溃代码……

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-08-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-04-13
              • 2019-07-13
              • 1970-01-01
              • 2020-03-13
              相关资源
              最近更新 更多