如何在C中调用具有完整IO的外部程序

时间:2017-02-28 15:09:27

标签: c io

如何在C中调用外部程序,以便我可以写入stdin并从stdout读取?有很多像这样的问题,但似乎没有人完全回答它。比方说,我有一些程序,我想让其他程序做一些事情,比如这个伪代码:

int * myinput = "this is my input"
FILE ** io = external_program("otherprogram arg1 arg2");
char c;
fprintf(io[0],myinput); // Writes my input to the programs stdin
while((c = fgetc(io[1])) != EOF) {
    printf("I just read %c from otherprogram!",c);
}

我无法找到它,我认为external_program之类的内容可能不存在。我怎么能得到类似的东西,我有一个程序在外部使用filedescriptors运行stdinstdout,如果可能的话stderr

这样我可以,例如,有一些程序用某种语言读取代码,将其编译为C或其他语言,并使用GCC来获取结果,而不必创建(并可能覆盖)文件,如这样:

FILE ** io = external_program("gcc -xc -");
FILE * output = open(output_file_path); // Program's own output

// ... generate C code, writing to io[0] ...

// Now write the output to our own output file
while((c = fgetc(io[1])) != EOF) {
    fputs(output,c);
}
close (output);

3 个答案:

答案 0 :(得分:1)

你需要两个管道,一个用于管道输入到孩子的stdin另一个用于阅读它stdout。在类似UNIX / Linux的环境中,创建子进程可能如下所示:

FILE    **p2open( const char *cmd, FILE **fpbuf )
{
    FILE    **result;
    int     fd1[2], fd2[2];
    int     ispipe1 = ERROR, ispipe2 = ERROR;
    pid_t   cpid;

    // open two pipes: Pipe1: parent reads, pipe2_: paretn writes

    if( (ispipe1 = pipe( fd1 )) == -1 ||
        (ispipe2 = pipe( fd2 )) == -1   )
    {
            return NULL;
    }


    switch( cpid = fork() ) {
    case -1:
            return NULL;


    case 0:                        /* Child                   */
            dup2( fd2[0], 0 );
            dup2( fd1[1], 1 );
            close( fd1[0] ); close( fd1[1] );
            close( fd2[0] ); close( fd2[1] );

            execlp( "/bin/sh", "sh", "-c", cmd, NULL );
            break;

    default:                        /* parent                       */
            if( (fpbuf[0] = fdopen( fd1[0], "r" )) == NULL ||
                (fpbuf[1] = fdopen( fd2[1], "w" )) == NULL   )
            {
                    result = NULL;
            } else {
                    result = fpbuf;
            }
    }

    if( ispipe1 != ERROR ) {
            close( fd1[1] );
            if( !result )           close( fd1[0] );
    }
    if( ispipe2 != ERROR ) {
            close( fd2[0] );
            if( !result )           close( fd2[1] );
    }
    return result;
}

您现在可以致电:

 FILE *pipefp[2];

 if( p2open( "mycmd", pipefp ) != NULL ) {
      // now you have pipefp[0] for readinf pipefp[1] for writing
      ..
 }

当然,您还应该实现匹配的p2close()功能,但我认为您可以管理

这是一个适用于Linux和solaris的测试主程:

int main(int argc, char *argv[] )
{
    FILE    *fp[2];
    int     c;

    if( p2open( "cat", fp ) != NULL ) {
            fputs( "go!\n", fp[1] );
            fclose( fp[1] );
            while( (c = fgetc( fp[0] )) != EOF ) {
                    fputc( c, stdout );
            }
    }

}

答案 1 :(得分:0)

这超越了vanilla C并进入了进程间通信,这是特定于平台的(也就是说,Windows的答案可能与* nix的答案不同)。

这是一个使用管道的简单* nix示例(取自Steve和Kay Robbins现在的绝版“Practical Unix Programming”):

/**
 * The following includes are specific to *nix
 */
#include <unistd.h>
#include <fcntl.h>

int main( int argc, char **argv )
{
  int fd[2]; // file descriptors for pipe
  pid_t childpid;

  pipe( fd );

  if ( (childpid = fork()) == 0 )
  {
    // this is the child process
    dup2( fd[1], STDOUT_FILENO );
    close( fd[0] );
    close( fd[1] );
    execl( "/bin/ls", "ls", "-l", argv[1], NULL );
    perror( "The exec of ls failed" );
  }
  else
  {
    // this is the parent process
    dup2( fd[0], STDIN_FILENO );
    close( fd[0] );
    close( fd[1] );
    execl( "/usr/bin/sort", "sort", "-n", "+4", NULL );
    perror( "The exec of sort failed" );
  }

  return 0;
}

这基本上是shell命令ls -l <path> | sort -n +4的C实现。使用ls描述符表和sort命令将fd的标准输出提供给pipe的标准输入。

正如所写,这是一个单向沟通渠道,这是我所做过的一切。我没有一个好的双向示例。

答案 2 :(得分:-1)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main()
{
    char ext_prog[]="prog name"; //your external program
    char arguments[]="args > file.txt"; //arguments
    strcat(ext_prog,arguments); //join the strings to ext_prog
    system(ext_prog); //execute on shell
}

这会将输出保存到file.txt,您可以对其进行解析。

编辑:还有其他方法可以解决这个问题。这是最重要的。尝试使用popen()FILE指针。