2

这个问题或多或少与C 中的嵌入式 perl perlapio 有关 -我认为我已经为 Windows 环境解决了与 STDIO 的互操作性。如果这个新问题也得到解决,我将发布一个完整的解决方案。

在链接的问题中, StoryTeller 给了我 使用PerlIO_findFILE()解决直接问题的提示,但是 Linux 上的相同代码表现得很奇怪。

Perldup2()在 Win32 上似乎有不同的行为,其中dup2()是一个宏 for win32_dup2(),据我所知,它只是使用dup2()from io.h

在 Win32 上,Perl 的版本在成功时返回零,在错误时返回非零,但在 Linux 上,dup2()将使用默认的 ANSI,而是返回新的文件描述符。然后,我将不得不检查errno一切是否正常。

如果调用PerlIO_findFILE()设置errno为“非法搜索”(errno 29 - ESPIPE),那么 after dupdup2等仍然设置为“非法搜索”,并且任何进一步的检查仍然会看到相同的错误pipeerrnoerrno

(实际上,一切都对我有用,因为没有实际错误。此外,通过检查的解决方案errno不是线程安全的,因为在系统调用和检查之间,另一个线程可能会重置 errno。)

请注意,我有

#define PERLIO_NOT_STDIO 0

实际上,我正在使用 Perl5.14.1。

我在这里做错了什么吗?

这是一个简化的代码片段:

stdOutFILE = PerlIO_findFILE(PerlIO_stderr()); // convert Perl's stdout to stdio FILE handle

fdStdOutOriginal = fileno(stdOutFILE);         // get descriptor

if ( fdStdOutOriginal >= 0 ) {

    relocatedStdOut = dup(fdStdOutOriginal);   // relocate stdOut for external writing

    if ( relocatedStdOut >= 0 )
    {
        if ( pipe(fdPipeStdOut) == 0 )         // create pipe for forwarding to stderr
        {
            // this has to be done on win32:
            // if ( dup2(fdPipeStdOut[1], fdStdOutOriginal)  == 0 ) // hang pipe on stdOut

            dup2(fdPipeStdOut[1], fdStdOutOriginal);

            if( errno == 0 ) {
                // do some funny stuff
            } else {
                // report error
            }
        }
    }
}
4

1 回答 1

3

errno除非C库调用或者系统调用报错是没有意义的,所以不能用来判断是否发生了错误。值得注意的是,这些调用不需要(通常也不会)errno在成功时重置。在调用之前清除甚至是不安全的,因为即使没有发生错误errno,调用也可能设置。errno

据我所知,Perl 的模拟返回dup2与 POSIX 相同的值(-1错误时,newfd成功时)。

#ifndef HAS_DUP2
int
dup2(int oldfd, int newfd)
{
#if defined(HAS_FCNTL) && defined(F_DUPFD)
    if (oldfd == newfd)
        return oldfd;
    PerlLIO_close(newfd);
    return fcntl(oldfd, F_DUPFD, newfd);
#else
#define DUP2_MAX_FDS 256
    int fdtmp[DUP2_MAX_FDS];
    I32 fdx = 0;
    int fd;

    if (oldfd == newfd)
        return oldfd;
    PerlLIO_close(newfd);
    /* good enough for low fd's... */
    while ((fd = PerlLIO_dup(oldfd)) != newfd && fd >= 0) {
        if (fdx >= DUP2_MAX_FDS) {
            PerlLIO_close(fd);
            fd = -1;
            break;
        }
        fdtmp[fdx++] = fd;
    }
    while (fdx > 0)
        PerlLIO_close(fdtmp[--fdx]);
    return fd;
#endif
}
#endif

(从 5.24.1 开始)

这意味着我们可以以独立于平台的方式检测错误,尽管您声称相反。因此,正确的用法是

if ( dup2(fdPipeStdOut[1], fdStdOutOriginal) >= 0 ) {
    //do some funny stuff
} else {
    //report error
}
于 2017-01-25T19:50:04.767 回答