(struct\u IO\u FILE*)是如何实现的->_IO_读取_基本设置?
为这个可能很奇怪的问题标题道歉。我不想让它看起来像一个标题为“C文件I/O如何在低级别工作?”的傻瓜。我希望我的问题是明确的 无论如何,当文件在C中是(struct\u IO\u FILE*)是如何实现的->_IO_读取_基本设置?,c,file,unix,glibc,stdio,C,File,Unix,Glibc,Stdio,为这个可能很奇怪的问题标题道歉。我不想让它看起来像一个标题为“C文件I/O如何在低级别工作?”的傻瓜。我希望我的问题是明确的 无论如何,当文件在C中是fopen'd时,它返回一个struct\u IO\u文件* FILE *f = fopen("hello.txt", "r"); printf("Fileno: %i\n", f->_fileno); // 3 我已经查看了libio.h和gdb的“tab”输出,并确认struct\u IO\u文件的内容如下所示: struct _IO_
fopen
'd时,它返回一个struct\u IO\u文件*
FILE *f = fopen("hello.txt", "r");
printf("Fileno: %i\n", f->_fileno); // 3
我已经查看了libio.h
和gdb的“tab”输出,并确认struct\u IO\u文件的内容如下所示:
struct _IO_FILE {
int _flags;
char* _IO_read_ptr;
char* _IO_read_end;
char* _IO_read_base; // <-- file contents
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;
unsigned short _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[...];
};
您可以看到它在哪里变换。在genops的某个地方。大概是\uuuuflow()
。但其来源没有回答任何问题:
int
__uflow (fp)
_IO_FILE *fp;
{
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
if (_IO_vtable_offset (fp) == 0 && _IO_fwide (fp, -1) != -1)
return EOF;
#endif
if (fp->_mode == 0)
_IO_fwide (fp, -1);
if (_IO_in_put_mode (fp))
if (_IO_switch_to_get_mode (fp) == EOF)
return EOF;
if (fp->_IO_read_ptr < fp->_IO_read_end)
return *(unsigned char *) fp->_IO_read_ptr++;
if (_IO_in_backup (fp))
{
_IO_switch_to_main_get_area (fp);
if (fp->_IO_read_ptr < fp->_IO_read_end)
return *(unsigned char *) fp->_IO_read_ptr++;
}
if (_IO_have_markers (fp))
{
if (save_for_backup (fp, fp->_IO_read_end))
return EOF;
}
else if (_IO_have_backup (fp))
_IO_free_backup_area (fp);
return _IO_UFLOW (fp);
}
libc_hidden_def (__uflow)
int
__uflow(fp)
_IO_文件*fp;
{
#如果定义| LIBC |定义| GLIBCPP |使用| WCHAR |
如果(_IO_vtable_offset(fp)=0&&u IO_fwide(fp,-1)!=-1)
返回EOF;
#恩迪夫
如果(fp->_模式==0)
_IO_fwide(fp,-1);
如果(输入模式(fp))
如果(_IO_切换到_get_模式(fp)=EOF)
返回EOF;
如果(fp->IO读取ptrIO读取结束)
返回*(无符号字符*)fp->_IO_read_ptr++;
如果(_IO_in_backup(fp))
{
_IO_开关_至_主_获取_区域(fp);
如果(fp->IO读取ptrIO读取结束)
返回*(无符号字符*)fp->_IO_read_ptr++;
}
如果(_IO_有_标记(fp))
{
如果(为备份保存(fp,fp->IO读取结束))
返回EOF;
}
否则如果(有备份(fp))
_IO空闲备份区(fp);
返回流(fp);
}
libc_hidden_def(uu uflow)
在gdb中测试每个调用,每个if检查都失败,所以我只能假设它返回\u IO\u UFLOW(fp)代码>。有趣的是,_IO_UFLOW是\u UFLOW
的一个宏包装器,所以…它在调用自己。它不是无限递归的。为什么?
这样一来,我就陷入了死胡同,因为我仍然无法解释fp->IO\u read\u ptr
是如何填写的。我只知道它发生在genops.c
的某个地方,在GDB中支持硬件观察点的平台上,您可以通过在fp->\u IO\u read\u base
上设置观察点来简单地回答这个问题。例如:
(gdb) watch -l fp->_IO_read_base
Hardware watchpoint 2: -location fp->_IO_read_base
(gdb) c
Continuing.
Hardware watchpoint 2: -location fp->_IO_read_base
Old value = 0x0
New value = 0x7ffff7ff7000 ""
__GI__IO_switch_to_get_mode (fp=fp@entry=0x602010) at genops.c:191
191 genops.c: No such file or directory.
(gdb) bt
#0 __GI__IO_switch_to_get_mode (fp=fp@entry=0x602010) at genops.c:191
#1 0x00007ffff7a8f670 in _IO_new_file_underflow (fp=0x602010) at fileops.c:602
#2 0x00007ffff7a841a5 in _IO_getdelim (lineptr=0x7fffffffdc88, n=0x7fffffffdc90, delimiter=10, fp=0x602010) at iogetdelim.c:77
#3 0x00000000004005b7 in main () at t.c:9
几乎可以肯定的是,libc_hidden_def(u uflow)
是一种棘手的弱引用类型,它允许您使用同名的其他函数重写函数。@paxdiablo您知道,有时我会质疑GNU开发人员的理智。当然,他们是一流的软件,但当你看源代码时,会发现宏意大利面、过多的空白、奇怪的缩进,以及各种可怕的、噩梦般难以阅读的代码,这些代码看起来就像是直接来自地狱的代码高尔夫挑战。有人想知道,他们是如何保持这种状态的。再说一次,也许他们已经。。。
(gdb) watch -l fp->_IO_read_base
Hardware watchpoint 2: -location fp->_IO_read_base
(gdb) c
Continuing.
Hardware watchpoint 2: -location fp->_IO_read_base
Old value = 0x0
New value = 0x7ffff7ff7000 ""
__GI__IO_switch_to_get_mode (fp=fp@entry=0x602010) at genops.c:191
191 genops.c: No such file or directory.
(gdb) bt
#0 __GI__IO_switch_to_get_mode (fp=fp@entry=0x602010) at genops.c:191
#1 0x00007ffff7a8f670 in _IO_new_file_underflow (fp=0x602010) at fileops.c:602
#2 0x00007ffff7a841a5 in _IO_getdelim (lineptr=0x7fffffffdc88, n=0x7fffffffdc90, delimiter=10, fp=0x602010) at iogetdelim.c:77
#3 0x00000000004005b7 in main () at t.c:9