这两天研究windows下,控制台窗口的输入输出,发现了一个问题,记录下来,希望对有需要的人有所帮助。
https://blog.youkuaiyun.com/dolphin98629/article/details/109846877
用_open_osfhandle,发现在VS 2017/2019不能用,又在vc6下测试了一下,发现能正常使用的,于是越来越好奇
找找原因,发现问题在FILE的定义里
VC6是这样定义的:
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
_CRTIMP FILE _iob[];
#define stdin (&_iob[0])
#define stdout (&_iob[1])
#define stderr (&_iob[2])
VS2015是这样定义的
struct __crt_stdio_stream_data
{
union
{
FILE _public_file;
char* _ptr;
};
char* _base;
int _cnt;
long _flags;
long _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
CRITICAL_SECTION _lock;
};
// FILE descriptors for stdin, stdout, and stderr
extern "C" __crt_stdio_stream_data _iob[_IOB_ENTRIES] =
{
// ptr _base, _cnt, _flag, _file, _charbuf, _bufsiz
{ nullptr, nullptr, 0, _IOALLOCATED | _IOREAD, 0, 0, 0 }, // stdin
{ nullptr, nullptr, 0, _IOALLOCATED | _IOWRITE, 1, 0, 0 }, // stdout
{ nullptr, nullptr, 0, _IOALLOCATED | _IOWRITE | _IOBUFFER_NONE, 2, 0, 0 }, // stderr
};
extern "C" FILE* __cdecl __acrt_iob_func(unsigned const id)
{
return &_iob[id]._public_file;
}
#define stdout (__acrt_iob_func(1))
//明显iob里面存放的是__crt_stdio_stream_data,不知道为什么不用定义好的?
明显2015的FILE只存放了个指针,就不能用vc6那样直接
*stdout=*hf了
但是也不是不能直接修改,只需要简单的扩展一下就可以
*(__crt_stdio_stream_data *)stdput=*(__crt_stdio_stream_data *)hf;
这样整个结构就会复制成功,编译运行,正常。
再来吐槽一下solaris,这个号称也不错的系统,里面的FILE是这么定义的:
/*
Solaris
*/
struct __FILE_TAG
{
#ifdef _STDIO_REVERSE
unsigned char *_ptr;
int _cnt;
#else
int _cnt;
unsigned char *_ptr;
#endif
unsigned char *_base;
unsigned char _flag;
unsigned char _file;
/* UNIX System file descriptor */
unsigned __orientation : 2;
unsigned __ionolock : 1;
unsigned __seekable : 1;
unsigned __filler : 4;
};
WTF,file竟然只用了个char,单进程最多只能打开255个文件。。。。
不过这个问题也不是不能解决,
参见我的另一篇blog,https://blog.youkuaiyun.com/trublemaker/article/details/50535779