写点什么

C++ 学习 ---cstdio 的源码学习分析 01- 类型定义

作者:桑榆
  • 2022 年 9 月 16 日
    上海
  • 本文字数:3559 字

    阅读完需:约 12 分钟

引言

cstdio 文件是 C++对 stdio.h 头文件的封装,Standard Input and Output Library,定义了一系列标准输入输出函数,包括文件操作(fopen/fclose 等),格式化打印(printf/scanf)等。通过该文件的学习,我们能够洞悉一些底层机制的本质,同时,也能够学习了解这些函数的实现方式,接下来,我们就一一学习这些函数的源码。

代码参考:因为这个头文件是相对比较特殊的,我们没有再采取阅读 AOSP 源码中 bionic 代码的方式,取而代之,我们参考 glibc 中的源码,这也是 linux 环境下,使用最为广泛的 C 标准库。

glibc 源码下载:https://www.gnu.org/software/libc/libc.html

git clone https://sourceware.org/git/glibc.gitcd glibcgit checkout master
复制代码

后文的源码阅读也都基于 glibc 代码的实现方式。

头文件位置

在 glibc 代码中搜索 stdio.h,可以看到如下文件:

   1      1  /home/sangyu/WorkSpace/Code/C++/glibc/include/bits/stdio.h <<<unknown>>>   2      1  /home/sangyu/WorkSpace/Code/C++/glibc/include/stdio.h <<<unknown>>>   3      1  /home/sangyu/WorkSpace/Code/C++/glibc/libio/bits/stdio.h <<<unknown>>>   4      1  /home/sangyu/WorkSpace/Code/C++/glibc/libio/stdio.h <<<unknown>>>
复制代码

通过查看头文件的包含关系:

glibc/include/bits/stdio.h include glibc/libio/bits/stdio.h 实现

glibc/include/stdio.h include glibc/libio/stdio.h 实现

实际上,实现函数定义以及相关接口的是 glibc/libio/stdio.h

类型定义与宏定义

stdio.h 头文件中定义了后续即将用到的类型与宏定义。

类型定义

FILE 类型---文件流对象

/glibc/libio/bits/types/FILE.h,发现了 FILE 的实际定义_IO_FILE,继续进行追踪

  4 struct _IO_FILE;  5                                                                           6 /* The opaque type of streams.  This is the definition used elsewhere.  */     7 typedef struct _IO_FILE FILE;
复制代码

/glibc/libio/bits/types/struct_FILE.h 中最终定义了_IO_FILE,其中的数据类型分为以下几类:

  • int _flags:用于控制文件流的访问权限(如读写执行,注意高位被_IO_MAGIC 占用,剩余位用来表示 flags)

  • streambuf 控制的:用于标识当前读写位置,buffer 大小等。

  • char *_IO_read_ptr:当前读取的指针

  • char *_IO_read_end:get 区域的末尾

  • char *_IO_read_base:putback+get 区域的开始

  • char *_IO_write_base:put 区域的开始

  • char *_IO_write_ptr:当前写入的指针

  • char *_IO_write_end:put 区域的末尾

  • char *_IO_buf_base:剩余数据的开始

  • char *_IO_buf_end:剩余数据的末尾

  • 备份和回退控制的:用于文件备份和回退控制的指针

  • char *_IO_save_base:非当前 get 区域的开始位置

  • char *_IO_backup_base:备份区域第一个合法字符

  • char *_IO_save_end:非当前 get 区域的末尾位置

  • struct _IO_marker *_markers:记录 buffer 中的位置(后面查看源码分析)

  • struct _IO_FILE *_chain:指向链接的下一个_IO_FILE 对象

  • int _fileno:file 的 number

  • int _flags2:扩展 flags

  • __off_t _old_offset:旧版的 offset,最终定义为(long int,32 位)

  • unsigned short _cur_column:当前列

  • signed char _vtable_offset:vtable 表的偏移

  • char _shortbuf[1]:只存储一个字符的 buffer

  • _IO_lock_t *_lock:访问 IO 锁注意:这里针对旧版的 IO_FILE 做了兼容,下面是新版增加的内容

  • __off64_t _offset:64 位 offset(定义为__int64_t,64 位)

  • 针对宽字符的处理 buff

  • struct _IO_codecvt *_codecvt:字符转换

  • struct _IO_wide_data *_wide_data:宽数据

  • struct _IO_FILE *_freeres_list:剩余的_IO_FILE list

  • size_t __pad5:对齐信息

  • int _mode:mode 信息

  • char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)]:预留位置保证追加部分是 16 个(加上 int _mode)sizeof(int)对齐的。

 46 /* The tag name of this struct is _IO_FILE to preserve historic 47    C++ mangled names for functions taking FILE* arguments. 48    That name should not be used in new code.  */ 49 struct _IO_FILE 50 { 51   int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */ 52  53   /* The following pointers correspond to the C++ streambuf protocol. */ 54   char *_IO_read_ptr;   /* Current read pointer */ 55   char *_IO_read_end;   /* End of get area. */ 56   char *_IO_read_base;  /* Start of putback+get area. */ 57   char *_IO_write_base; /* Start of put area. */ 58   char *_IO_write_ptr;  /* Current put pointer. */ 59   char *_IO_write_end;  /* End of put area. */ 60   char *_IO_buf_base;   /* Start of reserve area. */ 61   char *_IO_buf_end;    /* End of reserve area. */ 62  63   /* The following fields are used to support backing up and undo. */ 64   char *_IO_save_base; /* Pointer to start of non-current get area. */ 65   char *_IO_backup_base;  /* Pointer to first valid character of backup area */ 66   char *_IO_save_end; /* Pointer to end of non-current get area. */ 67  68   struct _IO_marker *_markers; 69  70   struct _IO_FILE *_chain; 71  72   int _fileno; 73   int _flags2; 74   __off_t _old_offset; /* This used to be _offset but it's too small.  */ 75  76   /* 1+column number of pbase(); 0 is unknown. */ 77   unsigned short _cur_column; 78   signed char _vtable_offset; 79   char _shortbuf[1]; 80  81   _IO_lock_t *_lock; 82 #ifdef _IO_USE_OLD_IO_FILE 83 }; 84  85 struct _IO_FILE_complete 86 { 87   struct _IO_FILE _file; 88 #endif 89   __off64_t _offset; 90   /* Wide character stream stuff.  */ 91   struct _IO_codecvt *_codecvt; 92   struct _IO_wide_data *_wide_data; 93   struct _IO_FILE *_freeres_list; 94   void *_freeres_buf; 95   size_t __pad5; 96   int _mode; 97   /* Make sure we don't get into trouble again.  */ 98   char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)]; 99 };
复制代码

_IO_marker 定义为包含下一个_IO_marker 指针,指向当前的 FILE* _sbuf,以及标识的位置_pos。

104 /* A streammarker remembers a position in a buffer. */105 struct _IO_marker {106   struct _IO_marker *_next;107   FILE *_sbuf;108   /* If _pos >= 0109  it points to _buf->Gbase()+_pos. FIXME comment */110   /* if _pos < 0, it points to _buf->eBptr()+_pos. FIXME comment */111   int _pos;112 };
复制代码

_IO_lock_t 定义包含 int lock; int cnt; void *owner;lock 用来指定锁,cnt 记录访问数量,owner 执向对应的 IO。

typedef struct { int lock; int cnt; void *owner; } _IO_lock_t;
复制代码

fpos_t 类型---file 特定位置的类型

根据具体的 offset 位数进行定义

 82 /* The type of the second argument to `fgetpos' and `fsetpos'.  */ 83 #ifndef __USE_FILE_OFFSET64 84 typedef __fpos_t fpos_t;                                                                                                                              85 #else 86 typedef __fpos64_t fpos_t; 87 #endif 88 #ifdef __USE_LARGEFILE64 89 typedef __fpos64_t fpos64_t; 90 #endif
复制代码

对应查看 glibc/libio/bits/types/__fpos_t.h,区别__fpos64_t 中__pos 被定义为__off64_t__mbstate_t 是转换状态信息,包括一个__count 信息和__value 信息(union 结构体进行 uint32 位到 4 个字符 char 的转换)

  7 /* The tag name of this struct is _G_fpos_t to preserve historic  8    C++ mangled names for functions taking fpos_t arguments.  9    That name should not be used in new code.  */ 10 typedef struct _G_fpos_t 11 { 12   __off_t __pos; //32位偏移,long int 13   __mbstate_t __state; 14 } __fpos_t;  10 typedef struct _G_fpos64_t 11 { 12   __off64_t __pos;//64位偏移,int_64t 13   __mbstate_t __state; 14 } __fpos64_t;  //glibc/wcsmbs/bits/types/__mbstate_t.h  8 #ifndef __WINT_TYPE__  9 # define __WINT_TYPE__ unsigned int 10 #endif 11  12 /* Conversion state information.  */ 13 typedef struct 14 {  15   int __count; 16   union 17   { 18     __WINT_TYPE__ __wch; 19     char __wchb[4]; 20   } __value;        /* Value so far.  */ 21 } __mbstate_t;
复制代码

size_t 类型---unsigned int 类型

这个就不需过多解释了,#define size_t unsigned int

发布于: 刚刚阅读数: 5
用户头像

桑榆

关注

北海虽赊,扶摇可接;东隅已逝,桑榆非晚! 2020.02.29 加入

Android手机厂商-相机软件系统工程师 爬山/徒步/Coding

评论

发布
暂无评论
C++学习---cstdio的源码学习分析01-类型定义_c++_桑榆_InfoQ写作社区