C++ 为什么我的程序在Linux上运行时系统调用失败,但在gdb中运行时成功?

C++ 为什么我的程序在Linux上运行时系统调用失败,但在gdb中运行时成功?,c++,c,gdb,C++,C,Gdb,我尝试运行一本书的示例代码。其功能是接受一行输入,并将其输出到标准输出和操作参数指定的文件中。 代码如下: #include <assert.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <fcntl.h> int main( int argc, char* argv[] ) { i

我尝试运行一本书的示例代码。其功能是接受一行输入,并将其输出到标准输出和操作参数指定的文件中。 代码如下:

#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

int main( int argc, char* argv[] )
{
    if ( argc != 2 )
    {
        printf( "usage: %s <file>\n", argv[0] );
        return 1;
    }
    int filefd = open( argv[1], O_CREAT | O_WRONLY | O_TRUNC, 0666 );
    assert( filefd > 0 );

    int pipefd_stdout[2];
        int ret = pipe( pipefd_stdout );
    assert( ret != -1 );

    int pipefd_file[2];
        ret = pipe( pipefd_file );
    assert( ret != -1 );

    //the first splice()
    ret = splice( STDIN_FILENO, NULL, pipefd_stdout[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE );
    assert( ret != -1 );

    ret = tee( pipefd_stdout[0], pipefd_file[1], 32768, SPLICE_F_NONBLOCK ); 
    assert( ret != -1 );

    //the second splice()       
    ret = splice( pipefd_file[0], NULL, filefd, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE );
    assert( ret != -1 );

    //the third splice()
    ret = splice( pipefd_stdout[0], NULL, STDOUT_FILENO, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE );
    printf("errno:%d\n",errno);
    assert( ret != -1 );


    close( filefd );
        close( pipefd_stdout[0] );
        close( pipefd_stdout[1] );
        close( pipefd_file[0] );
        close( pipefd_file[1] );
    return 0;
}
#包括

当我使用gdb运行代码时,它工作正常。这是剪报:

内核版本:4.19.163-1

gcc版本:10.2.0

gdb版本:10.1

我的编译命令:g++test.cpp-g-oliuxserver

我的运行命令:./LinuxServer test.txt

我的gdb命令:gdb LinuxServer

那么为什么我的程序在Linux上运行时splice系统调用失败,而在gdb中运行时成功呢?

在Linux手动splice(2)中,有一个错误描述:EINVAL目标文件以追加模式打开

终端中的stdout处于append模式,这就是第三个拼接系统调用失败的原因


为了解决这个问题,我们可以添加
fcntl(STDOUT\u FILENO,F\u SETFL,fcntl(STDOUT\u FILENO,F\u GETFL)和~O\u APPEND)在拼接系统调用之前。

不要断言可能失败的系统调用的返回值-这永远不是使用断言的正确方法-检查返回值并在失败后使用
perrno()
打印消息和
errno
值的说明。如果一本书确实使用了assert,那么也许你应该试着联系作者…@Antti Haapala谢谢你的建议,但我没有写这段代码,我的重点是为什么直接运行程序会出错,而运行GDB不会。好吧,无论如何,我找不到任何方法在我的5.4.0-62通用内核上复制EINVAL。。。