9

我用 C 编写了一个程序,该程序使用 printf 将消息发送到标准输出,但我无法将输出重定向到文件(从 bash 运行)。

我试过了:

./program argument >> program.out
./program argument > program.out
./program >> program.out argument
./program > program.out argument

在每种情况下,都会创建文件 program.out,但它仍然为空。执行结束后文件大小为0。

如果我在执行程序时省略了重定向:

./program argument

然后,使用 printf 发送到标准输出的所有消息都显示在终端中。

我有其他 C 程序,以这种方式重定向输出没有问题。跟程序本身有关系吗?随着论点通过?应该从哪里寻找问题?

C程序的一些细节:

  • 它不从标准输入读取任何内容
  • 它使用 BSD Internet 域套接字
  • 它使用 POSIX 线程
  • 它使用 sigaction 为 SIGINT 信号分配一个特殊的处理函数
  • 它向标准输出发送大量换行符(对于那些认为我应该刷新的人)

一些代码:

int main(int argc, char** argv)
{
    printf("Execution started\n");
    do
    {        
        /* lots of printf here */
    } while (1);
    /* Code never reached */
    pthread_exit(EXIT_SUCCESS);
}
4

5 回答 5

15

换行后刷新仅在打印到终端时有效,但在打印到文件时不一定有效。一个快速的谷歌搜索显示这个页面有更多的信息:http ://www.pixelbeat.org/programming/stdio_buffering/

请参阅标题为“默认缓冲模式”的部分。

毕竟,您可能必须添加一些对 fflush(stdout) 的调用。

您还可以使用setvbuf设置缓冲区大小和行为。

于 2009-02-01T00:34:51.057 回答
6

刷新缓冲区通常由函数处理,该函数通常由from main()exit()隐式调用。return您通过提高 SIGINT 来结束您的程序,显然默认的 SIGINT 处理程序不会刷新缓冲区。

看看这篇文章: 应用设计模式来简化信号处理。这篇文章主要是 C++,但在第 2 部分有一个有用的 C 示例,它展示了如何使用 SIGINT 优雅地退出程序。

至于为什么终端的行为与文件不同,请查看 Stevens的 UNIX 环境中的高级编程第 5.4 节关于缓冲。他说:

大多数实现默认为以下类型的缓冲。标准错误总是无缓冲的。如果所有其他流引用终端设备,则它们都是行缓冲的;否则,它们将被完全缓冲。本书中讨论的四个平台遵循标准 I/O 缓冲的这些约定:标准错误是无缓冲的,对终端设备开放的流是行缓冲的,所有其他流都是完全缓冲的。
于 2009-02-01T04:09:53.197 回答
3

当您检查重定向文件的内容时,程序是否已终止?如果它仍在运行,您的输出可能仍会在链上的某处缓冲,因此您不会在文件中看到它。

除此之外,以及迄今为止提供的其他答案,我认为是时候展示问题代码的代表性示例了。有太多深奥的可能性。

编辑

从示例代码的外观来看,如果您的打印量相对较小,那么您将被困在输出缓冲区中。每次写入后刷新以确保它已进入磁盘。通常,您可以拥有多达一页大小的未写入数据,否则。

在没有刷新的情况下,唯一可以确定磁盘上所有内容的时间是程序退出时。即使线程终止也不会这样做,因为这样的输出缓冲区不是每个线程的,它们是每个进程的。

于 2009-02-01T00:40:06.507 回答
0

建议:

  1. 也将 stderr 重定向到一个文件。
  2. 尝试 tail -f 您的输出文件。
  3. 打开一个文件并 fprintf 您的日志记录(以帮助弄清楚发生了什么)。
  4. 搜索 std* 文件句柄或 1-3 个文件描述符的任何手动关闭/复制/管道。
  5. 降低复杂性;在 printfs 工作之前,删除大量功能。然后阅读它们,直到它再次中断。继续,直到您确定罪魁祸首代码。
于 2009-02-01T05:13:20.400 回答
0

只是为了记录,在 Perl 中你会使用:

use IO::Handle;

flush STDOUT;
autoflush STDOUT;
于 2009-07-08T12:35:19.150 回答