IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> IO_FILE fopen -> 正文阅读

[数据结构与算法]IO_FILE fopen


前言

跟着raycp师傅学习IO_FILE,原文链接


源码

#include<stdio.h>

int main(){

    FILE*fp=fopen("test","wb");
    char *ptr=malloc(0x20);
    return 0;
}

跟进fopen,发现是IO_new_fopen函数,它调用的是__fopen_internal

_IO_FILE *
_IO_new_fopen (const char *filename, const char *mode)
{
  return __fopen_internal (filename, mode, 1);
}

跟进去__fopen_internal中,关键源码如下:

_IO_FILE *
__fopen_internal (const char *filename, const char *mode, int is32)
{
  struct locked_FILE
  {
    struct _IO_FILE_plus fp;
#ifdef _IO_MTSAFE_IO
    _IO_lock_t lock;
#endif
    struct _IO_wide_data wd;
  } *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));  ## step 1 分配内存

...

  _IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd, &_IO_wfile_jumps); ## step 2 null初始化结构体数据 
...

  _IO_JUMPS (&new_f->fp) = &_IO_file_jumps; ## 设置vtable为_IO_file_jumps
  _IO_file_init (&new_f->fp); ## step 3 将file结构体链接进去_IO_list_all

...
  # step 4 打开文件
  if (_IO_file_fopen ((_IO_FILE *) new_f, filename, mode, is32) != NULL)
    return __fopen_maybe_mmap (&new_f->fp.file);

}

所以fopen分为以下四部分

malloc分配内存空间。
_IO_no_init 对file结构体进行null初始化。
_IO_file_init将结构体链接进_IO_list_all链表。
_IO_file_fopen执行系统调用打开文件

malloc分配内存空间

分配struct locked_FILE大小的结构体,该结构体包含三个_IO_FILE_plus、_IO_lock_t、_IO_wide_data,IO_FILE_plus为使用的IO FILE的结构体。(其实我感觉这里指的应该都是file结构里的东西)

_IO_no_init 对file结构体进行null初始化

分配完空间后,就对结构体进行初始化

void
_IO_old_init (_IO_FILE *fp, int flags)
{ 
  fp->_flags = _IO_MAGIC|flags;
  fp->_flags2 = 0;
  fp->_IO_buf_base = NULL;
  fp->_IO_buf_end = NULL;
  fp->_IO_read_base = NULL;
  fp->_IO_read_ptr = NULL;
  fp->_IO_read_end = NULL;
  fp->_IO_write_base = NULL;
  fp->_IO_write_ptr = NULL;
  fp->_IO_write_end = NULL;
  fp->_chain = NULL; /* Not necessary. */

  fp->_IO_save_base = NULL;
  fp->_IO_backup_base = NULL;
  fp->_IO_save_end = NULL;
  fp->_markers = NULL;
  fp->_cur_column = 0;
...
  fp->_vtable_offset = 0;
...
}
void
_IO_no_init (_IO_FILE *fp, int flags, int orientation,
         struct _IO_wide_data *wd, const struct _IO_jump_t *jmp)
{
  _IO_old_init (fp, flags);
  fp->_mode = orientation;
  ...
      ## 初始化fp的_wide_data字段
      fp->_wide_data = wd;
      fp->_wide_data->_IO_buf_base = NULL;
      fp->_wide_data->_IO_buf_end = NULL;
      fp->_wide_data->_IO_read_base = NULL;
      fp->_wide_data->_IO_read_ptr = NULL;
      fp->_wide_data->_IO_read_end = NULL;
      fp->_wide_data->_IO_write_base = NULL;
      fp->_wide_data->_IO_write_ptr = NULL;
      fp->_wide_data->_IO_write_end = NULL;
      fp->_wide_data->_IO_save_base = NULL;
      fp->_wide_data->_IO_backup_base = NULL;
      fp->_wide_data->_IO_save_end = NULL;

      fp->_wide_data->_wide_vtable = jmp;
    ...
  fp->_freeres_list = NULL;
}

可以看出初始化_IO_file_plus和wide_data的内容

_IO_file_init将结构体链接进_IO_list_all

FILE结构体是通过_IO_list_all的单链表进行管理的
这里_IO_link_in函数的功能是检查FILE结构体是否包含_IO_LINKED标志,如果不包含则表示这个结构体没有链接进入_IO_list_all链表,
同时设置FILE结构体的_chain字段为之前的链表的值,
否则直接返回。
所以_IO_file_init主要功能是将FILE结构体链接进入_IO_list_all链表
在没执行_IO_file_init函数前_IO_list_all指向的是stderr结构体
执行完后可以看到_IO_list_all指向的是申请出来的结构体
FILE结构体的_chain字段指向了之前的stderr结构体
也就是说,把申请的堆块给到插入到stderr和list_all之间

_IO_file_fopen打开文件句柄

将FILE结构体链接到_IO_list_all链表后,程序返回到__fopen_internal中,接下来就调用_IO_new_file_fopen函数

_IO_FILE *
_IO_file_open (_IO_FILE *fp, const char *filename, int posix_mode, int prot,
           int read_write, int is32not64)
{
  int fdesc;

  ...
  # 调用系统函数open打开文件  
  fdesc = open (filename, posix_mode | (is32not64 ? 0 : O_LARGEFILE), prot);
  ...
  # 将文件描述符设置到FILE结构体的相应字段_fileno里
  fp->_fileno = fdesc;
  ...
  #再次调用_IO_link_in
  _IO_link_in ((struct _IO_FILE_plus *) fp);
  return fp;
}
libc_hidden_def (_IO_file_open)

函数的主要功能就是执行系统调用open打开文件,并将文件描述符赋值给FILE结构体的_fileno 字段,最后再次调用_IO_link_in函数,确保该结构体被链接进入_IO_list_all链表。

总结

(1)malloc的时候主要作用是申请内存空间
(2)_IO_no_init初始化阶段主要将wide_data和FILE_plus初始化
(3)_IO_file_init此处主要改变chain,将结构体链接进_IO_list_all链表,修改chain
(4)_IO_file_fopen执行系统调用打开文件,修改了file_no修改了vtable也是在此处设置成__GI__IO_file_jumps函数表,修改了flag
也就是四个地方:flag、chain、file_no、vtable

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-18 12:56:50  更:2021-08-18 12:57:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:19:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码