1.IO_FILE概述:
IO_FILE就是来描述IO文件结构体的,首先我们来看一下源码(2.35)
IO_FILE的相关源码是在libioP.h文件里面的:
/* We always allocate an extra word following an _IO_FILE.
This contains a pointer to the function jump table used.
This is for compatibility with C++ streambuf; the word can
be used to smash to a pointer to a virtual function table. */
struct _IO_FILE_plus
{
FILE file;
// 这里是常量指针 请记住和指针常量的区别
// 指针常量本质是常量 存储的是指针 也就是说其记录的指针不能被修改 但是指针指向的内容是可以修改的
// 常量指针是指针 只不过指针所指向的地址得是个常量 所以指针本身值可以被修改 但是其内容不可被修改
// 所以在开发者最初设想中 这里的vtable的值可以改变 但是它指向的内容是不可变的
// vtable指向的是类型为_IO_jump_t的常量数据
const struct _IO_jump_t *vtable;
};
我们最终描述文件流的数据结构是_IO_FILE_plus,这里面有FILE file结构体和 常量 _IO_jump_t,我们可以推断出来file成员应该是包含的该文件的关键数据,而vtable(虚表)就是各种操作函数的指针
每一个_IO_FILE结构体里面都有一个 _chain指针,指向下一个 _IO_FILE_plus结构体,通常情况下是这个样子的:
_IO_lsit_all -->IO_2_1_stderr .---->IO_2_1_stdout .----->IO_2_1_stdin
.......... | .......... | ..........
.......... | .......... | ..........
chain ___| chain ___| chain
.......... .......... ..........
当有新的文件被打开的时候,对应的_IO_FILE_plus结构体就会被插入到链首
2._IO_FILE:
下面就是_IO_FILE的源码:
struct _IO_FILE
{
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
/* The following pointers correspond to the C++ streambuf protocol. */
char *_IO_read_ptr; /* Current read pointer */
char *_IO_read_end; /* End of get area. */
char *_IO_read_base; /* Start of putback+get area. */
char *_IO_write_base; /* Start of put area. */
char *_IO_write_ptr; /* Current put pointer. */
char *_IO_write_end; /* End of put area. */
char *_IO_buf_base; /* Start of reserve area. */
char *_IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
int _flags2;
__off_t _old_offset; /* This used to be _offset but it's too small. */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
struct _IO_FILE_complete
{
struct _IO_FILE _file;
#endif
__off64_t _offset;
/* Wide character stream stuff. */
struct _IO_codecvt *_codecvt;
struct _IO_wide_data *_wide_data;
struct _IO_FILE *_freeres_list;
void *_freeres_buf;
size_t __pad5;
int _mode;
/* Make sure we don't get into trouble again. */
char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
};
_IO_FILE_complete
可以理解为_IO_FILE
的豪华加长版,其中的_wide_data
需要关注一下,有些手法会用到。
3._IO_jump_t:
vtable是一个指向_IO_jump_t结构体的指针。当打开一个文件的时候,相应的_IO_FIEL结构体会被创建并将其vtable字段指向对应文件类型的_IO_jump_t的地址。当我们需要执行文件操作的时候,可以通过_IO_FILE结构体里面的vtable字段获取相应的_IO_jump_t结构体。通常一个_IO_jump_t结构体包含了以下的函数指针:
struct _IO_jump_t
{
JUMP_FIELD(size_t, __dummy);
JUMP_FIELD(size_t, __dummy2);
JUMP_FIELD(_IO_finish_t, __finish);
JUMP_FIELD(_IO_overflow_t, __overflow);
JUMP_FIELD(_IO_underflow_t, __underflow);
JUMP_FIELD(_IO_underflow_t, __uflow);
JUMP_FIELD(_IO_pbackfail_t, __pbackfail);
/* showmany */
JUMP_FIELD(_IO_xsputn_t, __xsputn);
JUMP_FIELD(_IO_xsgetn_t, __xsgetn);
JUMP_FIELD(_IO_seekoff_t, __seekoff);
JUMP_FIELD(_IO_seekpos_t, __seekpos);
JUMP_FIELD(_IO_setbuf_t, __setbuf);
JUMP_FIELD(_IO_sync_t, __sync);
JUMP_FIELD(_IO_doallocate_t, __doallocate);
JUMP_FIELD(_IO_read_t, __read);
JUMP_FIELD(_IO_write_t, __write);
JUMP_FIELD(_IO_seek_t, __seek);
JUMP_FIELD(_IO_close_t, __close);
JUMP_FIELD(_IO_stat_t, __stat);
JUMP_FIELD(_IO_showmanyc_t, __showmanyc);
JUMP_FIELD(_IO_imbue_t, __imbue);
};
注意,程序里面有很多的_IO_jump_t结构体,不同的_IO_FILE_plus可能会采用不同的_IO_jump_t,比如我们的stdin/stdout/stderr使用_IO_file_jumps
Comments | NOTHING