开始IO啦!hgame week4的两道IO都摆烂放弃了,打算之后再系统学IO,how2heap暂时告一段落了就IO走起
基本结构体与全局变量 _IO_FILE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 struct  _IO_FILE  {int  _flags;		#define  _IO_file_flags _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;#if  0 int  _blksize;#else  int  _flags2;#endif  #define  __HAVE_COLUMN  unsigned  short  _cur_column;signed  char  _vtable_offset;char  _shortbuf[1 ];#ifdef  _IO_USE_OLD_IO_FILE struct  _IO_FILE_complete { struct  _IO_FILE  _file ;#endif  #if  defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001 # if  defined _LIBC || defined _GLIBCPP_USE_WCHAR_T struct  _IO_codecvt  *_codecvt ;struct  _IO_wide_data  *_wide_data ;struct  _IO_FILE  *_freeres_list ;void  *_freeres_buf;# else  void  *__pad1;void  *__pad2;void  *__pad3;void  *__pad4;# endif  size_t  __pad5;int  _mode;char  _unused2[15  * sizeof  (int ) - 4  * sizeof  (void  *) - sizeof  (size_t )];#endif  
重要成员:
_flags:高位字为IO_MAGIC,剩余的部分是flag 
_IO_read_ptr:input指针现在的位置 
_IO_read_end:input缓冲区的结束地址 
_IO_read_base:input缓冲区的基址 
_IO_write_base:output缓冲区的基址 
_IO_write_ptr:output指针现在的位置 
_IO_write_end:output指针的结束地址 
_IO_buf_base:缓冲区基址 
_IO_buf_end:缓冲区结束地址 
_chain:相当于fd指针,用于形成单链表串联所有的file stream 
_fileno:与文件相关的文件描述符 
_vtable_offset:存放虚表(virtual table)的偏移 
_offset:存放当前文件的偏移 
 
_IO_FILE_plus 1 2 3 4 5 6 7 struct  _IO_FILE_plus { const  struct  _IO_jump_t  *vtable ;
成员偏移:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 amd64:0x0 :'_flags' ,0x8 :'_IO_read_ptr' ,0x10 :'_IO_read_end' ,0x18 :'_IO_read_base' ,0x20 :'_IO_write_base' ,0x28 :'_IO_write_ptr' ,0x30 :'_IO_write_end' ,0x38 :'_IO_buf_base' ,0x40 :'_IO_buf_end' ,0x48 :'_IO_save_base' ,0x50 :'_IO_backup_base' ,0x58 :'_IO_save_end' ,0x60 :'_markers' ,0x68 :'_chain' ,0x70 :'_fileno' ,0x74 :'_flags2' ,0x78 :'_old_offset' ,0x80 :'_cur_column' ,0x82 :'_vtable_offset' ,0x83 :'_shortbuf' ,0x88 :'_lock' ,0x90 :'_offset' ,0x98 :'_codecvt' ,0xa0 :'_wide_data' ,0xa8 :'_freeres_list' ,0xb0 :'_freeres_buf' ,0xb8 :'__pad5' ,0xc0 :'_mode' ,0xc4 :'_unused2' ,0xd8 :'vtable' 
_IO_jump_t _IO_FILE_plus前一部分是_IO_FILE结构体,后一部分就是指向_IO_jump_t结构体的vtable指针,其实就是虚表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 struct  _IO_jump_t { size_t , __dummy);size_t , __dummy2);#if  0 #endif  
_IO_wide_data 为数据较多的流设置,根据宏
1 #if  defined _LIBC || defined _GLIBCPP_USE_WCHAR_T 
判断是否启用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 struct  _IO_wide_data { wchar_t  *_IO_read_ptr;	wchar_t  *_IO_read_end;	wchar_t  *_IO_read_base;	wchar_t  *_IO_write_base;	wchar_t  *_IO_write_ptr;	wchar_t  *_IO_write_end;	wchar_t  *_IO_buf_base;	wchar_t  *_IO_buf_end;		wchar_t  *_IO_save_base;	wchar_t  *_IO_backup_base;	wchar_t  *_IO_save_end;	__mbstate_t  _IO_state;__mbstate_t  _IO_last_state;struct  _IO_codecvt  _codecvt ;wchar_t  _shortbuf[1 ];const  struct  _IO_jump_t  *_wide_vtable ;
_IO_file_jumps 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 const  struct  _IO_jump_t  _IO_file_jumps  =
其中的宏定义如下,实际上就是各个函数的跳转表:
1 2 JUMP_INIT(dummy, 0 ), JUMP_INIT (dummy2, 0 )#define  JUMP_INIT(NAME,VALUE) VALUE 
_IO_list_all _IO_list_all->_IO_2_1_stderr_->_IO_2_1_stdout_->_IO_2_1_stdin_
1 2 3 struct  _IO_FILE_plus  *_IO_list_all  =
_IO_2_1_stderr_、_IO_2_1_stdout_和_IO_2_1_stdin_的定义其实在这(搜索的时候没找到)
珍爱生命,远离宏定义
 
1 2 3 4 5 0 , 0 , _IO_NO_WRITES);1 , &_IO_2_1_stdin_, _IO_NO_READS);2 , &_IO_2_1_stdout_, _IO_NO_READS+_IO_UNBUFFERED);
第一层宏定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # if  defined _LIBC || defined _GLIBCPP_USE_WCHAR_T #  define  DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \   static struct _IO_wide_data _IO_wide_data_##FD \     = { ._wide_vtable = &_IO_wfile_jumps }; \   struct _IO_FILE_plus NAME \     = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, &_IO_wide_data_##FD), \        &_IO_file_jumps}; # else  #  define  DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \   struct _IO_FILE_plus NAME \     = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, NULL), \        &_IO_file_jumps}; # endif  #endif  
第一层解宏定义
1 2 3 struct  _IO_FILE_plus  _IO_2_1_stdin_  =0 , 8 , 0 , NULL ), &_IO_file_jumps};struct  _IO_FILE_plus  _IO_2_1_stdout_  =4 , 1 , NULL ), &_IO_file_jumps};struct  _IO_FILE_plus  _IO_2_1_stderr_  =4 +2 , 2 , NULL ), &_IO_file_jumps};
第二层宏定义
1 2 3 4 5 6 7 #   define  FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \        { _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \ 	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (_IO_FILE *) CHAIN, FD, \ 	 0, _IO_pos_BAD, 0, 0, { 0 }, 0, _IO_pos_BAD, \ 	 0 } 
_IO_list_all_stamp 记录_IO_list_all单链表更改的次数
1 2 3 4 static  int  _IO_list_all_stamp;
fopen 函数调用流程图:
stdio.h中的fopen实际上是_IO_new_fopen
1 2 3 4 extern  _IO_FILE *_IO_new_fopen (const  char *, const  char *);#   define  fopen(fname, mode) _IO_new_fopen (fname, mode) 
或者iofopen.c中也有
1 2 3 # define  _IO_new_fopen fopen 
_IO_new_fopen又调用了__fopen_internal
1 2 3 4 5 6 7 const  char  *filename, const  char  *mode)return  __fopen_internal (filename, mode, 1 );
__fopen_internal的流程如下:
malloc分配内存 
调用_IO_no_init null初始化结构体数据 
设置vtable为_IO_file_jumps 
将_IO_FILE结构体链入_IO_list_all 
打开文件1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 const  char  *filename, const  char  *mode, int  is32)struct  locked_FILE   { struct  _IO_FILE_plus  fp ;#ifdef  _IO_MTSAFE_IO #endif  struct  _IO_wide_data  wd ;struct  locked_FILE *) malloc  (sizeof  (struct  locked_FILE));if  (new_f == NULL )return  NULL ;#ifdef  _IO_MTSAFE_IO #endif  #if  defined _LIBC || defined _GLIBCPP_USE_WCHAR_T 0 , 0 , &new_f->wd, &_IO_wfile_jumps);#else  1 , 0 , NULL , NULL );#endif  #if   !_IO_UNIFIED_JUMPTABLES NULL ;#endif  if  (_IO_file_fopen ((_IO_FILE *) new_f, filename, mode, is32) != NULL )return  __fopen_maybe_mmap (&new_f->fp.file);free  (new_f);return  NULL ;
 
 
_IO_no_init 调用了_IO_old_init,然后进行了一系列null初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 void int  flags, int  orientation,struct  _IO_wide_data *wd, const  struct  _IO_jump_t *jmp)#if  defined _LIBC || defined _GLIBCPP_USE_WCHAR_T if  (orientation >= 0 )NULL ;NULL ;NULL ;NULL ;NULL ;NULL ;NULL ;NULL ;NULL ;NULL ;NULL ;else struct  _IO_wide_data *) -1L ;#endif  NULL ;
_IO_old_init 也是一系列null初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 void int  flags)0 ;NULL ;NULL ;NULL ;NULL ;NULL ;NULL ;NULL ;NULL ;NULL ; NULL ;NULL ;NULL ;NULL ;0 ;#if  _IO_JUMPS_OFFSET 0 ;#endif  #ifdef  _IO_MTSAFE_IO if  (fp->_lock != NULL )#endif  
_IO_file_init _IO_file_init也是一个宏,实际调用的函数是_IO_new_file_init
1 2 3 # define  _IO_new_file_init _IO_file_init 
_IO_new_file_init进行了一些初始化并调用了_IO_link_in
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void struct  _IO_FILE_plus *fp)-1 ;
1 2 3 4 5 #define  CLOSED_FILEBUF_FLAGS \   (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET) 
_IO_link_in _IO_link_in将_IO_FILE_plus结构体链入_IO_list_all单链表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 void struct  _IO_FILE_plus *fp)if  ((fp->file._flags & _IO_LINKED) == 0 )#ifdef  _IO_MTSAFE_IO #endif  #ifdef  _IO_MTSAFE_IO NULL ;0 );#endif  
_IO_file_fopen 这其实也是个宏定义,实际上调用的函数是_IO_new_file_fopen
1 2 3 # define  _IO_new_file_fopen _IO_file_fopen 
_IO_new_file_fopen的过程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 const  char  *filename, const  char  *mode,int  is32not64)int  oflags = 0 , omode;int  read_write;int  oprot = 0666 ;int  i;#ifdef  _LIBC const  char  *cs;const  char  *last_recognized;#endif  if  (_IO_file_is_open (fp))return  0 ;switch  (*mode)case  'r' :break ;case  'w' :break ;case  'a' :break ;default :return  NULL ;#ifdef  _LIBC #endif  for  (i = 1 ; i < 7 ; ++i)switch  (*++mode)case  '\0' :break ;case  '+' :#ifdef  _LIBC #endif  continue ;case  'x' :#ifdef  _LIBC #endif  continue ;case  'b' :#ifdef  _LIBC #endif  continue ;case  'm' :continue ;case  'c' :continue ;case  'e' :#ifdef  O_CLOEXEC #endif  continue ;default :continue ;break ;if  (result != NULL )#ifndef  __ASSUME_O_CLOEXEC if  ((fp->_flags2 & _IO_FLAGS2_CLOEXEC) != 0  && __have_o_cloexec <= 0 )int  fd = _IO_fileno (fp);if  (__have_o_cloexec == 0 )int  flags = __fcntl (fd, F_GETFD);0  ? -1  : 1 ;if  (__have_o_cloexec < 0 )#endif  strstr  (last_recognized + 1 , ",ccs=" );if  (cs != NULL )struct  gconv_fcts  fcts ;struct  _IO_codecvt  *cc ;char  *endp = __strchrnul (cs + 5 , ',' );char  *ccs = malloc  (endp - (cs + 5 ) + 3 );if  (ccs == NULL )int  malloc_err = errno;  void ) _IO_file_close_it (fp);return  NULL ;char  *) __mempcpy (ccs, cs + 5 , endp - (cs + 5 ))) = '\0' ;if  (__wcsmbs_named_conv (&fcts, ccs[2 ] == '\0' 5 ) : ccs) != 0 )void ) _IO_file_close_it (fp);free  (ccs);return  NULL ;free  (ccs);1 );1 );memset  (&fp->_wide_data->_IO_state, '\0' , sizeof  (__mbstate_t ));memset  (&fp->_wide_data->_IO_last_state, '\0' , sizeof  (__mbstate_t ));0 ].__invocation_counter = 0 ;0 ].__internal_use = 1 ;0 ].__flags = __GCONV_IS_LAST;0 ].__statep = &result->_wide_data->_IO_state;0 ].__invocation_counter = 0 ;0 ].__internal_use = 1 ;0 ].__flags0 ].__statep =1 ;return  result;
_IO_file_open 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 const  char  *filename, int  posix_mode, int  prot,int  read_write, int  is32not64)int  fdesc;#ifdef  _LIBC if  (__glibc_unlikely (fp->_flags2 & _IO_FLAGS2_NOTCANCEL))0  : O_LARGEFILE), prot);else 0  : O_LARGEFILE), prot);#else  #endif  if  (fdesc < 0 )return  NULL ;if  ((read_write & (_IO_IS_APPENDING | _IO_NO_READS))0 , _IO_seek_end);if  (new_pos == _IO_pos_BAD && errno != ESPIPE)return  NULL ;struct  _IO_FILE_plus *) fp);return  fp;
__fopen_maybe_mmap 当有_G_HAVE_MMAP定义时使用,根据读写模式决定操作方式?没看懂。最终返回_IO_FILE结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #ifdef  _G_HAVE_MMAP if  ((fp->_flags2 & _IO_FLAGS2_MMAP) && (fp->_flags & _IO_NO_WRITES))if  (fp->_mode <= 0 )else #endif  return  fp;
_IO_un_link 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 void struct  _IO_FILE_plus *fp)if  (fp->file._flags & _IO_LINKED)struct  _IO_FILE  **f ;#ifdef  _IO_MTSAFE_IO #endif  if  (_IO_list_all == NULL )else  if  (fp == _IO_list_all)struct  _IO_FILE_plus *) _IO_list_all->file._chain;else for  (f = &_IO_list_all->file._chain; *f; f = &(*f)->_chain)if  (*f == (_IO_FILE *) fp)break ;#ifdef  _IO_MTSAFE_IO NULL ;0 );#endif  
fread 流程图如下:
执行fread函数时实际上执行的是_IO_fread函数,_IO_fread函数又调用了_IO_sgetn函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void  *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp)0 );if  (bytes_requested == 0 )return  0 ;char  *) buf, bytes_requested);return  bytes_requested == bytes_read ? count : bytes_read / size;
_IO_sgetn函数又调用了_IO_XSGETN函数,实际上就是跳转表中的__xsgetn函数
1 2 3 4 5 6 7 8 9 10 void  *data, _IO_size_t n)return  _IO_XSGETN (fp, data, n);#define  _IO_XSGETN(FP,DATA,N) JUMP2 (__xsgetn, FP, DATA, N) 
_IO_file_xsgetn执行步骤如下:
如果缓冲区为空调用_IO_doallocbuf分配缓冲区 
如果want<=have则读入want个字节并将want清零,否则执行以下步骤 
如果还有字节剩余,则读入剩余have字节 
如果存在backup则调用_IO_switch_to_main_get_area调用backup 
如果缓冲区容量大于需求则调用__underflow向缓冲区中读入 
将所有读写相关指针指向缓冲区基址 
计算count,直接从文件中读取count字节 
错误处理 
调整文件偏移1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 _IO_size_tvoid  *data, _IO_size_t n)char  *s = data;if  (fp->_IO_buf_base == NULL )if  (fp->_IO_save_base != NULL )free  (fp->_IO_save_base);while  (want > 0 )if  (want <= have)memcpy  (s, fp->_IO_read_ptr, want);0 ;else if  (have > 0 )#ifdef  _LIBC #else  memcpy  (s, fp->_IO_read_ptr, have);#endif  if  (_IO_in_backup (fp))continue ;if  (fp->_IO_buf_basesize_t ) (fp->_IO_buf_end - fp->_IO_buf_base))if  (__underflow (fp) == EOF)break ;continue ;if  (fp->_IO_buf_base)if  (block_size >= 128 )if  (count <= 0 )if  (count == 0 )else break ;if  (fp->_offset != _IO_pos_BAD)return  n - want;
 
 
_IO_doallocbuf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void if  (fp->_IO_buf_base)return ;if  (!(fp->_flags & _IO_UNBUFFERED) || fp->_mode > 0 )if  (_IO_DOALLOCATE (fp) != EOF)return ;1 , 0 );
_IO_file_doallocate 主要过程就是malloc一块缓冲区然后调用_IO_setb设定缓冲区相关指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 int char  *p;struct  stat64  st ;#ifndef  _LIBC if  (__glibc_unlikely (_IO_cleanup_registration_needed != NULL ))#endif  if  (fp->_fileno >= 0  && __builtin_expect (_IO_SYSSTAT (fp, &st), 0 ) >= 0 )if  (S_ISCHR (st.st_mode))if  (#ifdef  DEV_TTY_P #endif  #if  _IO_HAVE_ST_BLKSIZE if  (st.st_blksize > 0 )#endif  malloc  (size);if  (__glibc_unlikely (p == NULL ))return  EOF;1 );return  1 ;
_IO_setb 设置缓冲区指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void char  *b, char  *eb, int  a)if  (f->_IO_buf_base && !(f->_flags & _IO_USER_BUF))free  (f->_IO_buf_base);if  (a)else 
_IO_switch_to_main_get_area 将缓冲区移至backup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void char  *tmp;
__underflow 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 int #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 )-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))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))return  _IO_UNDERFLOW (fp);
_IO_new_file_underflow 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 int #if  0 if  (fp->_flags & _IO_EOF_SEEN)return  (EOF);#endif  if  (fp->_flags & _IO_NO_READS)return  EOF;if  (fp->_IO_read_ptr < fp->_IO_read_end)return  *(unsigned  char  *) fp->_IO_read_ptr;if  (fp->_IO_buf_base == NULL )if  (fp->_IO_save_base != NULL )free  (fp->_IO_save_base);if  (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))#if  0 #else  if  ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))#endif  if  (count <= 0 )if  (count == 0 )else 0 ;if  (count == 0 )return  EOF;if  (fp->_offset != _IO_pos_BAD)return  *(unsigned  char  *) fp->_IO_read_ptr;
其他输入函数 scanf scanf的函数调用栈如下,最终是使用跳转表中的_IO_new_file_underflow实现输入的:
1 2 3 4 5 6 read
gets 和scanf差不多
1 2 3 4 5 read
fwrite 函数调用流程:
执行fwrite函数实际上执行的是_IO_write函数,_IO_write又调用了_IO_sputn
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const  void  *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp)0 ;0 );if  (request == 0 )return  0 ;if  (_IO_vtable_offset (fp) != 0  || _IO_fwide (fp, -1 ) == -1 )const  char  *) buf, request);if  (written == request || written == EOF)return  count;else return  written / size;
_IO_sputn其实是调用跳转表中的_IO_file_xsputn(实际上是_IO_new_file_xsputn),步骤如下:
将目标数据拷贝至输出缓冲区 
如果缓冲区还有空间则先吧数据拷贝进输出缓冲区 
如果还有数据剩余则说明缓冲区未建立或者缓冲区已满,调用_IO_OVERFLOW建立或清空缓冲区 
判断数据是否大块,是则先调用new_do_write输出小块数据,然后调用_IO_default_xsputn将剩余数据拷贝进缓冲区1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 const  void  *data, _IO_size_t n)const  char  *s = (const  char  *) data;int  must_flush = 0 ;0 ;if  (n <= 0 )return  0 ;if  ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))if  (count >= n)const  char  *p;for  (p = s + n; p > s; )if  (*--p == '\n' )1 ;1 ;break ;else  if  (f->_IO_write_end > f->_IO_write_ptr)if  (count > 0 )if  (count > to_do)#ifdef  _LIBC #else  memcpy  (f->_IO_write_ptr, s, count);#endif  if  (to_do + must_flush > 0 )if  (_IO_OVERFLOW (f, EOF) == EOF)return  to_do == 0  ? EOF : n - to_do;128  ? to_do % block_size : 0 );if  (do_write)if  (count < do_write)return  n - to_do;if  (to_do)return  n - to_do;
 
 
_IO_new_file_overflow _IO_OVERFLOW实际上就是跳转表中的_IO_new_file_overflow
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 int int  ch)if  (f->_flags & _IO_NO_WRITES) return  EOF;if  ((f->_flags & _IO_CURRENTLY_PUTTING) == 0  || f->_IO_write_base == NULL )if  (f->_IO_write_base == NULL )if  (__glibc_unlikely (_IO_in_backup (f)))size_t  nbackup = f->_IO_read_end - f->_IO_read_ptr;if  (f->_IO_read_ptr == f->_IO_buf_end)if  (f->_mode <= 0  && f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))if  (ch == EOF)return  _IO_do_write (f, f->_IO_write_base,if  (f->_IO_write_ptr == f->_IO_buf_end ) if  (_IO_do_flush (f) == EOF)return  EOF;if  ((f->_flags & _IO_UNBUFFERED)'\n' ))if  (_IO_do_write (f, f->_IO_write_base,return  EOF;return  (unsigned  char ) ch;
_IO_new_do_write _IO_do_write实际上是_IO_new_do_write(宏定义),调用了new_do_write,_IO_file_xsputn后续步骤也调用了这个函数
1 2 3 4 5 6 7 8 int const  char  *data, _IO_size_t to_do)return  (to_do == 0 0  : EOF;
new_do_write 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 static new_do_write  (_IO_FILE *fp, const  char  *data, _IO_size_t to_do) if  (fp->_flags & _IO_IS_APPENDING)else  if  (fp->_IO_read_end != fp->_IO_write_base)1 );if  (new_pos == _IO_pos_BAD)return  0 ;if  (fp->_cur_column && count)1 , data, count) + 1 ;0 return  count;
_IO_new_file_write _IO_SYSWRITE实际上就是跳转表中的_IO_file_write(_IO_new_file_write),调用系统调用清空缓冲区
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 const  void  *data, _IO_ssize_t n)while  (to_do > 0 )0 )if  (count < 0 )break ;void  *) ((char  *) data + count);if  (f->_offset >= 0 )return  n;
_IO_default_xsputn 调用_IO_OVERFLOW清空缓冲区
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 const  void  *data, _IO_size_t n)const  char  *s = (char  *) data;if  (more <= 0 )return  0 ;for  (;;)if  (f->_IO_write_ptr < f->_IO_write_end)if  (count > more)if  (count > 20 )#ifdef  _LIBC #else  memcpy  (f->_IO_write_ptr, s, count);#endif  else  if  (count)char  *p = f->_IO_write_ptr;for  (i = count; --i >= 0 ; )if  (more == 0  || _IO_OVERFLOW (f, (unsigned  char ) *s++) == EOF)break ;return  n - more;
注意一点 main函数返回的时候_IO_cleanup会调用_IO_flush_all_lockp函数最终调用系统函数write清空缓冲区之后讨论
fclose 函数调用流程图:
fclose实际上是_IO_new_fclose
1 2 3 # define  _IO_new_fclose fclose 
_IO_new_fclose函数的执行流程如下:
调用_IO_un_link将fp从_IO_list_all单链表中摘除 
调用_IO_file_close_it关闭文件并释放缓冲区 
调用_IO_FINISH(_IO_new_file_finish)确定_IO_FILE已从链表中取出且缓冲区已释放 
如果fp不是标准输入、输出或错误,则释放fp结构体1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 int int  status;#if  SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1) if  (_IO_vtable_offset (fp) != 0 )return  _IO_old_fclose (fp);#endif  if  (fp->_IO_file_flags & _IO_IS_FILEBUF)struct  _IO_FILE_plus *) fp);if  (fp->_IO_file_flags & _IO_IS_FILEBUF)else -1  : 0 ;if  (fp->_mode > 0 )#if  _LIBC struct  _IO_codecvt  *cc  =#endif  else if  (_IO_have_backup (fp))if  (fp != _IO_stdin && fp != _IO_stdout && fp != _IO_stderr)0 ;free (fp);return  status;
 
 
_IO_un_link 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 void struct  _IO_FILE_plus *fp)if  (fp->file._flags & _IO_LINKED)struct  _IO_FILE  **f ;#ifdef  _IO_MTSAFE_IO #endif  if  (_IO_list_all == NULL )else  if  (fp == _IO_list_all)struct  _IO_FILE_plus *) _IO_list_all->file._chain;else for  (f = &_IO_list_all->file._chain; *f; f = &(*f)->_chain)if  (*f == (_IO_FILE *) fp)break ;#ifdef  _IO_MTSAFE_IO NULL ;0 );#endif  
_IO_file_close_it 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 int int  write_status;if  (!_IO_file_is_open (fp))return  EOF;if  ((fp->_flags & _IO_NO_WRITES) == 0 0 )else 0 ;int  close_status = ((fp->_flags2 & _IO_FLAGS2_NOCLOSE) == 0 0 );#if  defined _LIBC || defined _GLIBCPP_USE_WCHAR_T if  (fp->_mode > 0 )if  (_IO_have_wbackup (fp))NULL , NULL , 0 );NULL , NULL , NULL );NULL , NULL );#endif  NULL , NULL , 0 );NULL , NULL , NULL );NULL , NULL );struct  _IO_FILE_plus *) fp);-1 ;return  close_status ? close_status : write_status;
_IO_file_close 直接进行系统调用
1 2 3 4 5 6 7 int return  close_not_cancel (fp->_fileno);
_IO_setb 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void char  *b, char  *eb, int  a)if  (f->_IO_buf_base && !(f->_flags & _IO_USER_BUF))free  (f->_IO_buf_base);if  (a)else 
_IO_new_file_finish 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void int  dummy)if  (_IO_file_is_open (fp))if  (!(fp->_flags & _IO_DELETE_DONT_CLOSE))0 );
_IO_default_finish 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 void int  dummy)struct  _IO_marker  *mark ;if  (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))free  (fp->_IO_buf_base);NULL ;for  (mark = fp->_markers; mark != NULL ; mark = mark->_next)NULL ;if  (fp->_IO_save_base)free  (fp->_IO_save_base);NULL ;struct  _IO_FILE_plus *) fp);#ifdef  _IO_MTSAFE_IO if  (fp->_lock != NULL )#endif