观察glibc里面的fopen函数(删去了多线程相关的内容,假定_IO_MTSAFE_IO0),实际原型是_IO_new_fopen,又调用了__fopen_internal,里面的逻辑很简单,从堆上分配一个locked_FILE

// libio/stdio.h, line #268
// 导出部分
/* Open a file and create a new stream for it.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern FILE *fopen (const char *__restrict __filename,
            const char *__restrict __modes) __wur;

// libio/iofopen.c, line #34
# define _IO_new_fopen fopen

// libio/iofopen.c, line #94
_IO_FILE *
_IO_new_fopen (const char *filename, const char *mode)
{
  return __fopen_internal (filename, mode, 1);
}

// libio/iofopen.c, line #59
_IO_FILE *
__fopen_internal (const char *filename, const char *mode, int is32)
{
  struct locked_FILE
  {
    struct _IO_FILE_plus fp;
    struct _IO_wide_data wd;
  } *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));

  if (new_f == NULL)
    return NULL;
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
  _IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd, &_IO_wfile_jumps);
#else
  _IO_no_init (&new_f->fp.file, 1, 0, NULL, NULL);
#endif
  _IO_JUMPS (&new_f->fp) = &_IO_file_jumps;
  _IO_file_init (&new_f->fp);
#if  !_IO_UNIFIED_JUMPTABLES
  new_f->fp.vtable = NULL;
#endif
  if (_IO_file_fopen ((_IO_FILE *) new_f, filename, mode, is32) != NULL)
    return __fopen_maybe_mmap (&new_f->fp.file);

  _IO_un_link (&new_f->fp);
  free (new_f);
  return NULL;
}
    然后调用`_IO_no_init`,作用是初始化`_IO_FILE`以及下面的`_wide_data`(各种指针清零),其中`_wide_data`的vtable被初始化为`_IO_wfile_jumps`。

    之后又把`_IO_FILE`的vtable设为`_IO_file_jumps`,再调用`_IO_file_init`,实际是`_IO_new_file_init`的宏,里面把fp初始化为未打开状态,并且用`_IO_link_in`把它链进`_IO_list_all`
// libio/fileops.c, line #142
void
_IO_new_file_init (struct _IO_FILE_plus *fp)
{
  /* POSIX.1 allows another file handle to be used to change the position
     of our file descriptor.  Hence we actually don't know the actual
     position before we do the first fseek (and until a following fflush). */
  fp->file._offset = _IO_pos_BAD;
  fp->file._IO_file_flags |= CLOSED_FILEBUF_FLAGS;

  _IO_link_in (fp);
  fp->file._fileno = -1;
}
libc_hidden_ver (_IO_new_file_init, _IO_file_init)

// libio/genops.c, line #95
void
_IO_link_in (struct _IO_FILE_plus *fp)
{
  if ((fp->file._flags & _IO_LINKED) == 0)
    {
      fp->file._flags |= _IO_LINKED;
      fp->file._chain = (_IO_FILE *) _IO_list_all;
      _IO_list_all = fp;
      ++_IO_list_all_stamp;
    }
}
libc_hidden_def (_IO_link_in)
    返回后之后是执行`_IO_file_fopen`,`_IO_new_file_fopen`的宏定义,内容就不贴了= =,其实就是把字符串的`mode`转成标准`sys_open`,如果出现问题,就调`_IO_un_link`从`_IO_list_all`删除,然后`free`掉申请出来的`locked_FILE` ,至此`fopen`结束