首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用write()或fwrite()将数据写入终端(stdout)?

如何使用write()或fwrite()将数据写入终端(stdout)?
EN

Stack Overflow用户
提问于 2020-07-02 14:46:36
回答 3查看 7.3K关注 0票数 3

我正试图加快我的C程序,以更快地吐出数据。

目前,我正在使用printf()向外界提供一些数据。它是一个连续的数据流,因此我无法使用返回(数据)。

如何使用write()fwrite()将数据分发给console而不是文件?

总的来说,我的设置由用C编写的程序组成,它的输出到python脚本,在那里将进一步处理数据。我形成了一根管子:

代码语言:javascript
运行
复制
./program_in_c | script_in_python

通过使用更多的处理器内核,这给Raspberry Pi带来了额外的好处。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-07-02 14:50:39

代码语言:javascript
运行
复制
#include <unistd.h>

       ssize_t write(int fd, const void *buf, size_t count);

write()写入从buf开始的缓冲区到文件描述符fd所引用的文件的字节数。

标准的输出文件描述符是:至少在linux中!在调用写入系统调用以确保清除所有先前的garabge之前,也要使用刷新stdoutput缓冲区。

代码语言:javascript
运行
复制
fflush(stdout); // Will now print everything in the stdout buffer
write(1, buf, count);

使用fwrite

代码语言:javascript
运行
复制
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

函数fwrite()将nmemb数据项(每个大小的字节长)写入流所指向的流,从ptr给定的位置获取它们。

代码语言:javascript
运行
复制
fflush(stdout);
int buf[8];
fwrite(buf, sizeof(int), sizeof(buf), stdout);

如欲进一步阅读,请参考手册页,请参阅以下链接:

复写

票数 3
EN

Stack Overflow用户

发布于 2020-07-03 21:40:07

好吧,试图克服stdio.h包中已经使用的缓冲系统几乎没有成功。如果您尝试将fwrite()与更大的缓冲区一起使用,您可能不会赢得更多的时间,并且使用比所需的内存更多的内存,因为stdio.h会选择最佳的缓冲区大小,以接近要写入数据的文件系统。

像下面这样的简单程序将显示速度是无关紧要的,因为stdio已经在缓冲输出。

代码语言:javascript
运行
复制
#include <stdio.h>
int
main()
{
    int c;

    while((c = getchar()) >= 0)
        putchar(c);
}

如果您尝试以上和下面的程序:

代码语言:javascript
运行
复制
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main()
{
    char buffer[512];
    int n;

    while((n = read(0, buffer, sizeof buffer)) > 0)
        write(1, buffer, n);

    if (n < 0) {
        perror("read");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

您将看到没有意义的差别,甚至,第一个程序将更快,尽管它是做I/O的基础上的每一个字符。(正如B.Kernighan& Dennis在她的第一版“C编程语言”中写的那样),很可能第一个程序将获胜。

read()write()的调用分别涉及一个系统调用,缓冲区大小由您决定。单独的getchar()putchar()调用并不是这样。它们只是将接收到的字符存储在内存缓冲区中,然后打印它们,它们的大小是由基于文件系统的stdio.h库实现决定的,一旦缓冲区充满数据,它就会刷新缓冲区。如果在第二个程序中增加缓冲区大小,您将看到在一定程度上增加缓冲区的效果更好,但在此之后,您将不会看到速度的进一步增长。对于执行实际I/O和选择一个非常大的缓冲区所涉及的时间而言,对库的调用次数很小,将占用系统中的大量内存(从这个意义上说,Raspberry Pi内存被限制为1Gb或ram),如果由于缓冲区太大而导致交换结束,您将完全失败。

大多数文件系统都有首选的缓冲区大小,因为内核确实会提前写入(在顺序读取时,内核读取的内容比您要求的要多,因为在您使用数据之后,您将继续阅读更多),这会影响到最佳缓冲区大小。为此,stat(2)系统调用告诉您什么是最佳缓冲区大小,stdio在选择实际缓冲区大小时使用它。

不要以为你会比上面列出的程序更好(或者更好)。即使你使用了足够大的缓冲区。

不正确的(或有效的)是将执行缓冲(像所有stdio包)的调用与基本的系统调用(比如read(2)write(2) --正如我已经看到的建议您在write(2)之后使用fflush(3),这是完全不连贯的--不缓冲数据)--混合在一起--没有缓冲数据)--没有收入(如果您使用printf(3)进行部分调用和部分使用write(2),则可能会得到错误的输出排序(这在管道中发生得更多,就像您计划的那样),因为缓冲区不是面向行的--这是stdio中缓冲输出的另一个特性--)

最后,我建议您阅读Dennis和Rob的“Unix编程环境”。它将教给您很多unix,但非常好的一点是,它将教会您完美地使用stdio包和unix文件系统调用来进行读写。幸运的是,你可以在互联网上的.pdf上找到它。

下一个程序向您展示缓冲的效果:

代码语言:javascript
运行
复制
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main()
{
    int i;
    char *sep = "";

    for (i = 0; i < 10; i++) {
        printf("%s%d", sep, i);
        sep = ", ";
        sleep(1);
    }
    printf("\n");
}

人们会假设您将(在终端上)看到程序,将数字0写入9,由,隔开,并以一秒钟的间隔执行。

但是由于缓冲,您所观察到的是完全不同的,您将看到您的程序在没有在终端上写任何东西的情况下等待10秒,最后,当程序结束时,shell再次向您显示提示符,并在最后一次写入所有内容,包括最后一行结束。

如果将程序更改为以下内容:

代码语言:javascript
运行
复制
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main()
{
    int i;
    char *sep = "";

    for (i = 0; i < 10; i++) {
        printf("%s%d", sep, i);
        fflush(stdout);
        sep = ", ";
        sleep(1);
    }
    printf("\n");
}

您将看到预期的输出,因为您已经告诉stdio在每次循环传递时刷新缓冲区。在这两个程序中,您都对printf(3)进行了10次调用,但在最后只有一个write(2)来编写完整的缓冲区。在第二个版本中,您强迫stdio在每个printf之后执行一个这样的write(2),并在程序通过循环时显示数据。

要小心,因为stdio的另一个特性可能会使您感到困惑,比如当您打印到终端设备时,会在每个\n上刷新输出,但是当您通过管道运行它时,只有当缓冲区完全填满时,它才会这样做。这样可以节省系统调用(例如,在FreeBSD中,stdio选择的缓冲区大小大约为32 in,足够大到迫使两个块达到write(2)和最佳(超过该大小的效果不会更好)。

票数 2
EN

Stack Overflow用户

发布于 2020-07-02 14:56:52

C中的控制台输出与文件的工作方式几乎相同。一旦包含了stdio.h,就可以在控制台输出上写入,名为stdout (用于“标准输出”)。最后,声明如下:

代码语言:javascript
运行
复制
printf("hello world!\n");

与以下相同:

代码语言:javascript
运行
复制
char str[] = "hello world\n";

fwrite(str, sizeof(char), sizeof(str) - 1, stdout);
fflush(stdout);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62699018

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档