为什么无法替换标准输出(stdout)?

3

出于教育目的,我正在尝试替换标准流stdout、stdin和stderr。我首先查找了流的数据类型,发现其追溯到具有以下成员(gdb ptype _IO_FILE)的struct _IO_FILE:

type = struct _IO_FILE {
    int _flags;
    char *_IO_read_ptr;
    char *_IO_read_end;
    char *_IO_read_base;
    char *_IO_write_base;
    char *_IO_write_ptr;
    char *_IO_write_end;
    char *_IO_buf_base;
    char *_IO_buf_end;
    char *_IO_save_base;
    char *_IO_backup_base;
    char *_IO_save_end;
    struct _IO_marker *_markers;
    struct _IO_FILE *_chain;
    int _fileno;
    int _flags2;
    __off_t _old_offset;
    short unsigned int _cur_column;
    signed char _vtable_offset;
    char _shortbuf[1];
    _IO_lock_t *_lock;
    __off64_t _offset;
    void *__pad1;
    void *__pad2;
    void *__pad3;
    void *__pad4;
    size_t __pad5;
    int _mode;
    char _unused2[20];
}

然后我尝试复制stdout指针的内存内容:

_IO_FILE f1 = {._flags = -72540028, ._offset = -1, ._old_offset = -1, ._fileno = 1, ._chain = stdin, ._lock = stdout->_lock, .__pad2 = stdout->__pad2 };
_IO_FILE *f2 = stdout;
_IO_FILE *f3 = malloc(sizeof(_IO_FILE));
memcpy(f3, stdout, sizeof(_IO_FILE));

fprintf(&f1, "f1\n"); // doesn't work 
fprintf(f2, "f2\n"); // works
fprintf(f3, "f3\n"); // doesn't work

然而,只有指针赋值不会崩溃。通过gdb比较内存内容,所有内容共享相同的结构成员内容。
尽管这个问题可能与平台相关:fprintf和其他库函数是否只比较标准流的指针?
编辑:我怀疑这是一个实现或平台相关的问题,并且由于所有的意见都表明这是一个问题,我接受了提出问题可能原因的答案。
编辑2:为了缩小问题范围:我正在使用版本为12.04的64位ubuntu和EGLIBC版本为2.15。

5
这完全取决于具体实现。要找到答案,您应该检查您的实现源代码(这本质上也是其他人为回答这个问题所必须做的事情...)。 - Oliver Charlesworth
1
@OliCharlesworth 但是有人可以通过说明需要检查什么以及在哪里搜索来提供帮助,就像你所做的那样。这已经是答案了。这不是关闭的原因。 - Gangnus
1
在Linux设备上进行了调查。成功地停止了分段错误。看起来stdout结构保持了锁定状态。仅复制该结构是不够的。请参见第43行:http://searchcode.com/codesearch/view/18356174 - Ben Crowhurst
1
我个人不喜欢在问题还没有得到解决的时候就将其暂停。 - Ben Crowhurst
@Corvusoft:“挂起”不是由任何一个人决定的,需要5个个人投票。此外,整个意义在于,如果问题得到改进,那么它可以被重新打开。 - Oliver Charlesworth
我试图通过命名实现来改进问题,以便更好地得到答案。然而,问题仍然被暂停了。请问我还需要改进问题的哪个部分? - box
1个回答

1

根据Corvus的评论,在Linus系统中,锁与流相关联,因此复制FILE数据结构会干扰锁语义。

(我建议不要立即接受此答案,以便给Corvus时间输入答案。)


旧假设:

我怀疑在你的C实现中,FILE对象的位置被用作其含义的一部分。例如,可能有一个它们的数组,并且从指向该数组第一个元素的指针中减去指向FILE对象的指针以找到其在数组中的索引。然后,这个索引被用作系统调用(如write)中的文件号。

当你分配新空间时,它不在这个数组中,指针算术运算会得出错误的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接