【问题标题】:How do I run a program from another program and pass data to it via stdin in c or c++?如何从另一个程序运行一个程序并通过 c 或 c++ 中的标准输入将数据传递给它?
【发布时间】:2014-02-09 10:57:47
【问题描述】:

假设我有一个.exe,比如说sum.exe。现在说sum.exe 的代码是

void main ()
{
 int a,b;
 scanf ("%d%d", &a, &b);
 printf ("%d", a+b);
}

我想知道如何从另一个 c/c++ 程序运行该程序并通过标准输入传递输入,就像他们在 ideone 等在线编译器网站中所做的那样,我在其中键入代码并在文本框中提供标准输入数据和该数据被程序使用 scanf 或 cin 接受。另外,我想知道是否有任何方法可以从启动它的原始程序中读取该程序的输出。

【问题讨论】:

  • 你看过管道以及它们是如何工作的吗?
  • dup2 可能会将您带到您想去的地方。祝你好运。
  • 您可以使用std::system从命令行执行您可以执行的所有操作,包括重定向输入和输出。

标签: c++ c ipc stdin


【解决方案1】:

根据上面发布的一些答案和各种教程/手册,我只是在 Linux 中使用 pipe() 和 shell 重定向来完成此操作。策略是首先创建一个管道,调用另一个程序并将被调用者的输出从stdout重定向到管道的一端,然后读取管道的另一端。只要被调用者写给stdout就不需要修改了。

在我的应用程序中,我需要读取用户输入的数学表达式,调用独立计算器并检索其答案。这是我演示重定向的简化解决方案:

#include <string>
#include <unistd.h>
#include <sstream> 
#include <iostream> 

// this function is used to wait on the pipe input and clear input buffer after each read    
std::string pipeRead(int fd) { 
    char data[100];
    ssize_t size = 0;
    while (size == 0) {
        size = read(fd, data, 100);
    }
    std::string ret = data;
    return ret;
}

int main() {
    // create pipe
    int calculatorPipe[2];
    if(pipe(calculatorPipe) < 0) {
        exit(1);
    }
    
    std::string answer = "";
    std::stringstream call;

    // redirect calculator's output from stdout to one end of the pipe and execute
    // e.g. ./myCalculator 1+1 >&8
    call << "./myCalculator 1+1 >&" << calculatorPipe[1];
    system(call.str().c_str());

    // now read the other end of the pipe
    answer = pipeRead(calculatorPipe[0]);
    std::cout << "pipe data " << answer << "\n";

    return 0;
}

显然还有其他解决方案,但这是我在不修改被调用程序的情况下能想到的。不过,Windows 中的情况可能有所不同。

一些有用的链接:

https://www.geeksforgeeks.org/pipe-system-call/

https://www.gnu.org/software/bash/manual/html_node/Redirections.html

【讨论】:

    【解决方案2】:

    如何执行此操作(您必须检查错误,即pipe()==-1dup()!=0 等,我不会在下面的 sn-p 中执行此操作)。

    此代码运行您的程序“sum”,将“2 3”写入其中,然后读取 sum 的输出。接下来,它将输出写入标准输出。

    #include <iostream>
    #include <sys/wait.h>
    #include <unistd.h>
    
    int main() {
    
        int parent_to_child[2], child_to_parent[2];
        pipe(parent_to_child);
        pipe(child_to_parent);
    
        char name[] = "sum";
        char *args[] = {name, NULL};
        switch (fork()) {
    
        case 0:
            // replace stdin with reading from parent
            close(fileno(stdin));
            dup(parent_to_child[0]);
            close(parent_to_child[0]);
    
            // replace stdout with writing to parent
            close(fileno(stdout));
            dup(child_to_parent[1]);
            close(child_to_parent[1]);
    
            close(parent_to_child[1]); // dont write on this pipe
            close(child_to_parent[0]); // dont read from this pipe
    
            execvp("./sum", args);
            break;
    
        default:
            char msg[] = "2 3\n";
    
            close(parent_to_child[0]); // dont read from this pipe
            close(child_to_parent[1]); // dont write on this pipe
    
            write(parent_to_child[1], msg, sizeof(msg));
            close(parent_to_child[1]);
    
            char res[64];
            wait(0);
            read(child_to_parent[0], res, 64);
            printf("%s", res);
            exit(0);
        }
    }
    

    我正在做@ugoren 在their answer 中建议的事情:

    • 为进程之间的通信创建两个管道
    • 分叉
    • 使用dup 将标准输入和标准输出替换为管道末端
    • 通过管道发送数据

    【讨论】:

      【解决方案3】:

      这是我的解决方案,它奏效了:

      sum.cpp

      #include "stdio.h"
      int main (){
        int a,b;
        scanf ("%d%d", &a, &b);
        printf ("%d", a+b);
        return 0;
      }
      

      test.cpp

      #include <stdio.h>
      #include <stdlib.h>
      
      int main(){
        system("./sum.exe < data.txt");
        return 0;
      }
      

      数据.txt

      3 4
      

      试试这个解决方案:)

      【讨论】:

        【解决方案4】:

        在名称以 X 结尾的平台(即非 Windows)上的 C 中,关键组件是:

        1. pipe - 返回一对文件描述符,以便可以从另一个读取写入的内容。

        2. fork - 将进程分叉为两个,都继续运行相同的代码。

        3. dup2 - 重新编号文件描述符。有了这个,你可以把管道的一端变成标准输入或标准输出。

        4. exec - 停止运行当前程序,开始运行另一个程序,在同一个进程中。

        把它们结合起来,你就能得到你想要的。

        【讨论】:

        • 您的意思可能是“在 Linux 中,关键组件是”。
        • @Lundin,您的意思可能是“在 POSIX 环境中,...”;)
        • @Shahbaz 因为除了 *nix 之外没有人关心 POSIX,这本质上是一回事。
        • @Lundin,我不想争论。只是让您知道*nix 不仅仅是Linux。反正我只是开玩笑说的,算了。
        • @Shahbaz GNU 不是 Unix? :)
        【解决方案5】:

        我知道的最简单的方法是使用popen() 函数。它适用于 Windows 和 UNIX。另一方面,popen() 只允许单向通信。

        例如,要将信息传递给sum.exe(尽管您将无法读取结果),您可以这样做:

        #include <stdio.h>
        #include <stdlib.h>
        
        int main()
        {
            FILE *f;
        
            f = popen ("sum.exe", "w");
            if (!f)
            {
                perror ("popen");
                exit(1);
            }
        
            printf ("Sending 3 and 4 to sum.exe...\n");
            fprintf (f, "%d\n%d\n", 3, 4);
        
            pclose (f);
            return 0;
        }
        

        【讨论】:

          【解决方案6】:

          如何做到这一点取决于平台。

          在 windows 下,使用 CreatePipe 和 CreateProcess。您可以从 MSDN 中找到示例: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx

          Linux/Unix下,可以使用dup()/dup2()

          一种简单的方法是使用终端(如 Windows 中的命令提示符)并使用 |重定向输入/输出。

          例子:

          program1 | program2
          

          这会将 program1 的输出重定向到 program2 的输入。 要检索/输入日期,您可以使用临时文件,如果您不想使用临时文件,则必须使用管道。

          对于 Windows,(使用命令提示符):

          program1 <input >output 
          

          对于Linux,您可以使用tee实用程序,您可以在linux终端输入man tee查看详细说明

          【讨论】:

            【解决方案7】:

            听起来您来自 Windows 环境,因此这可能不是您要寻找的答案,但您可以在命令行中使用管道重定向运算符“|”将一个程序的标准输出重定向到另一个程序的标准输入。 http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx?mfr=true

            您可能最好在 bash shell 中工作,您可以在 Windows 上使用 cygwin http://cygwin.com/ 获得它

            此外,您的示例看起来像是 C++ 和 C 的混合体,而 main 的声明并不是两者都可以接受的标准。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-09-02
              • 2015-01-06
              • 2011-10-17
              • 1970-01-01
              • 2017-02-03
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多