cin.tellg从管道接收输入时返回-1

时间:2018-12-30 21:17:50

标签: c++ linux fork exec

在某些情况下,我需要将子进程的输出通过管道传递到ifstream

我都尝试使用以下方法从文件描述符创建ifstream:How to construct a c++ fstream from a POSIX file descriptor?

并且我还试图使用从子stderr到我自己的stdin的管道,并使用cin作为我的流。

在两种情况下,我打电话给Tellg都得到-1。

这是我的代码,其中包含从子stderr到父stdin的管道:

#include <iostream>

#include <unistd.h>
#include <sys/wait.h>

using namespace std;

int
main()
{
    int mypipe[2];

    pipe(mypipe);

    dup2(mypipe[0], STDIN_FILENO);
    dup2(mypipe[1], STDERR_FILENO);

    __pid_t pid = fork();

    if(pid == 0)
    {
        // this is a process that outputs stuff into std::err
        char* argv[] = {"copy-feats", nullptr};

        int ret = execvp(argv[0], argv);

        exit(ret);
    }

    int status;
    waitpid(pid, &status, WNOHANG);

    cin.clear(); // attempting to clear the error state. Not working.
    long size = cin.tellg();
    cout << size << endl;
}

所以我说过Tellg的输出是-1。

如果我尝试使用getline(cin,some_string),我实际上将能够看到子程序的输出。

我尝试通过管道创建流,但仍然给我-1。

这是我使用的代码:

#include <iostream>
#include <fstream>
#include <ext/stdio_filebuf.h>

#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>

#define READ_FD  0
#define WRITE_FD 1

using namespace std;

using FilebufType = __gnu_cxx::stdio_filebuf<std::ifstream::char_type>;

int
main()
{
    int mypipe[2];

    pipe(mypipe);

    __pid_t pid = fork();

    if(pid == 0)
    {
        dup2(mypipe[WRITE_FD], STDERR_FILENO);
        char* argv[] = {"copy-feats", nullptr};

        int ret = execvp(argv[0], argv);

        exit(ret);
    }

    int status;
    waitpid(pid, &status, WNOHANG);

    FilebufType filebuf(mypipe[READ_FD], std::ios::in);
    istream is(&filebuf);

    is.clear();
    auto size = is.tellg();
    cout << size << endl;
}

谢谢。

1 个答案:

答案 0 :(得分:1)

实际上,tellg()仅在输入流是实际文件时才返回实际​​文件位置。也就是说,当输入流是std::ifstream时,然后仅在基础文件是纯文件时。

管道和其他非普通文件没有文件位置的概念。

在您正在使用的Linux上,tellg()通常是通过使用lseek(2)来实现的(间接的,但在这里不相关),而lseek(2)'s documentation明确指定它返回一个{{ 1}}错误,如果文件描述符是管道。错误返回最终将转化为ESPIPE返回-1。