【问题标题】:How to read until EOF from STDOUT in C?如何从 C 中的 STDOUT 读取直到 EOF?
【发布时间】:2020-10-24 05:01:01
【问题描述】:

#1:给定命令,我不知道标准输出产生的输出大小。

#2:我不想像这样使用 char 数组

char buffer[1024];

因为这会导致内存不足或浪费。

#3:如果我使用像这样的字符指针

char *buffer;

我将不得不为它分配内存

buffer = (char *)malloc(1024 * sizeof(char));

#4:如果我在 while 循环中使用 getc(),比如

char *buf, c;
int i=0, j=1;
int pipefd[2];
int  stdout_bk;
code[message_read] = '\0';
stdout_bk = dup(fileno(stdout));
pipe(pipefd);
dup2(pipefd[1], STDOUT_FILENO);

system(code);
close(pipefd[1]);

dup2(stdout_bk, STDOUT_FILENO);
buf = (char*)malloc(sizeof(char));

while(c!=End_Of_File) // What should I replace End_Of_File with?
{
    c = getc(pipefd[0]);
    buf = (char*)realloc(buf, j * sizeof(char));
    buf[i] = c;
    i++;
    j++;
}

我不知道标准输出数据的 End_Of_file 是什么。

PS:程序运行一个命令,例如 system("setarch x86_64 -R dd if=/proc/self/maps | grep bin/dd") 或 system("ls -al") 我需要得到标准输出。为此,我使用了 dup2 并且需要将输出通过管道传输到缓冲区。

注意:输出可以是可变长度的。

【问题讨论】:

  • 我认为关于这个话题已经有很多问题了,所以只是评论:将c声明为int(不是char),将while(c!=End_Of_File)替换为while ((c=getc(stdin)) != EOF)(用任何东西替换stdin),并在下一行去掉对get()的调用。
  • 为每个字符调用 realloc 并不常见,即使我认为它在内部进行了优化以分配更大的块。
  • 为什么不使用 POSIX 标准函数 popen() 来获取包含您给它的命令的输出的文件流。您的管道有很多管道问题;使用popen() 将避免其中的大部分。
  • 您的系统有多少主内存,您认为 1 KiB 缓冲区会造成问题?在大多数非嵌入式系统上,您可以分配 64 KiB 而不会造成任何问题。您可能希望避免堆栈上的兆字节缓冲区;默认情况下,堆栈在 Windows 上限制为 1 MiB(在类 Unix 系统上通常为 8 MiB)。
  • #4 中的代码仅适用于非常小的输出,因为在执行的命令终止之前它不会开始读取。这意味着它依靠管道充当整个输出的缓冲区。管道确实有缓冲作用,但它们这样做的能力是有限的;一旦你填满了管道缓冲区,写入它就会阻塞,这意味着你的程序将有效地死锁。如果您使用的是 Linux,请阅读man 7 pipe 了解更多详细信息(特别注意“管道容量”)。或者阅读 IPC 上的任何好文章。

标签: c string dynamic malloc stdout


【解决方案1】:

你的代码有很多问题:

  • c 必须使用 int 类型定义
  • getc() 不能将系统句柄作为参数,您必须将其包装在带有 fdopen()FILE* 中。
  • 对于getc() 返回的数据,End_Of_File 是简单的EOF 并且c 必须具有int 类型才能使文件结束测试可靠。
  • 一次重新分配一个字节的数组效率低下,并且可能比按块重新分配更浪费
  • 更重要的是,如果您打算将此缓冲区用作 C 字符串,则可能需要为空终止符分配一个额外的字节。
  • system() 命令的输出将被限制为系统管道缓冲区的大小,通常约为 5KB,因此您的程序会因任何较大的输出而卡住。
  • popen() 用于您的目的要简单得多。

这是一个简化版:

#include <stdio.h>
#include <stdlib.h>

int main() {
    char code[] = "ls -lR";
    char *buf = NULL;
    int c;
    int i = 0;
    FILE *fp;

    fp = popen(code, "r");
    if (fp == NULL) {
        fprintf(stderr, "popen error\n");
        return 1;
    }
    while ((c = getc(fp)) != EOF) {
        buf = (char *)realloc(buf, i + 2);
        if (buf == NULL) {
            fprintf(stderr, "out of memory\n");
            pclose(fp);
            return 1;
        }
        buf[i++] = (char)c;
    }
    pclose(fp);
    printf("output: %d bytes\n", i);
    if (buf != NULL) {
        buf[i] = '\0';
        fputs(buf, stdout);
    }
    free(buf);        
    return 0;
}

【讨论】:

    猜你喜欢
    • 2010-09-17
    • 2011-04-15
    • 1970-01-01
    • 1970-01-01
    • 2017-10-18
    • 1970-01-01
    • 2017-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多