当前位置: 首页 > C, C/C++ > 正文

探秘stdio.h 实现与使用

前言

之前,总结了stdio.h的设计,不得不说它真是C 库中内容最多的库,所以我只能再开这篇,将他们一分为二来学习了。这篇主要介绍的就是stdio库的实现。

__start

stdio 的实现。它的实现其实在于两个部分:

数据结构FILE 的内容

与操作系统相互作用以执行输入输出的低级源语。

一些通用的结构

</h3>
#define   _NULL   (void *) 0     /*value for NULL */

#define   _FNAMAX    64        /*value for FILENAME_MAX*/

#define   _FOPMAX    32        /*value  for FOPEN_MAX */

#define    _TNAMAX  16         /*value  for L_tmpnam*/

FILE

我们经常使用 FILE 作为C库文件描述符,现在我们具体的来看看它到底内部是由那些东西做到的。现在的C 标准库可能已经变化,所以我会摘录《C标准库》的东西,同时我也会摘录较新的glibc库的东西。

首先是《C标准库》的内容


_Mode    流的状态位集合

_Handle   操作系统打开文件后得到的文件描述符或者句柄

_Buf        指向流缓冲区首地址的指针,如果没有分配缓冲区,则是一个空指针。

_Next       指向读操作或写操作的下一个字符的指针,它不可能是一个空指针。

_Rend       指向超出读取范围的第一个字符指针,不可能是一个空指针。

_Rsave     如果字符回退,就保存指针_Rend

_Wend     指向超出可写数据范围的第一个字符,它不可能是一个空指针。

_Back       保存回退字符的栈

_Cbuf       当没有其他缓冲区可用时,能够使用单字符缓冲区

_Nback     记录回退字符个数

_Tmpnam   指向文件关闭时要删除的临时文件名的指针,或者一个空指针。

现在看看现阶段的C 库实现


typedef struct _IO_FILE FILE;

首先FILE 的真名叫 _IO_FILE, 现在看这个。


struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
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;
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */

#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];

/* char* _save_gptr; char* _save_egptr; */

_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

可以看出现在的C标准库做出了修改但是我们探究原理,所以还是主要看原来的。

下面给出几个实现的例子,但是这里依然调用了UNIX 的源语,所以我们在这里只需要了解它的一些实现原理就好,在     kernel文件系统   专题我会再好好分析下Linux 源语。

这是一个自己定义的头文件。


#ifndef _STDIO_H
#define _STDIO_H

#define _NULL (void *)  0

#define _FNAMAX 64

#define _FOPMAX 32

#define _TNAMAX 16

#define NULL _NULL

#define _IOFBF 0

#define _IOLBF 1

#define _IONBF 2

#define BUFSIZE 512

#define EOF -1

#define FILENAME_MAX _FNAMAX

#define FOPEN_MAX _FOPMAX

#define L_tmpnam _TNAMAX

#define TMP_MAX 32

#define SEEK_SET 0

#define SEEK_CUR 1

#define SEEK_END 2

#define stdin _Files[0]

#define stdout _Files[1]

#define stderr _Files[2]

typedef _Sizet size_t

typedef struct {
unsigned long _off;
}fpos_t;

typedef struct {
unsigned short _Mode;
short _Handle;
unsigned char *_Buf,*_Bend ,*_Next;
unsigned char *_Rend, *_Rsave, *_Wend;
unsigned char _Back[2],_Cbuf,_Nback;
char * _Tmpnam;
}FILE;
void clearerr(FILE *);
int fclose(FILE *);
int feof(FILE *);
int ferror(FILE *);
int fflush(FILE *);
int fgetc(FILE *);
int fgetpos(FILE *,fpos_t *);
char *fgets(char *,int ,FILE *);
FILE *fopen(const char *,const char *);
int fputc(int,FILE *);
int fputs(const char *,FILE *);
size_t fread(void *,size_t ,size_t ,FILE *);
FILE *freopen(const char *,const char *,FILE *);
int fscanf(FILE *, const char *,...);

int fseek(FILE *,long ,int);
int fsetpos(FILE *,const fpos_t *);
long ftell(FILE *);
size_t fwrite(const void *,size_t ,size_t,FILE *);
int getc(FILE *);
int getchar(void);
char *gets(char *);
void perror(const char *);

int printf(const char *,...);
int putc(int ,FILE *);
int putchar(int);
int puts(const char *);
int remove(const char *);
int rename(const char *,const char *);
void rewind(FILE *);

int scanf(const char *,...);
void setbuf(FILE *,char *);
int setvbuf(FILE *,char *,int ,size_t);
int sprintf(char *,const char *,...);
int sscanf(const char *,const char *,...);
FILE *tmpfile(void);
char *tmpnam(char *);
int ungetc(int ,FILE *);
int vfprintf(FILE *,const char *,char *);
int vprintf(const char *,char *);
int vsprintf(char *,const char *,char *);
long _Fgpos(FILE * ,fpos_t *);
int _Fspos(FILE *,const fpos_t *,long ,int);
FILE * _Files[FOPEN_MAX];

#define fgetpos(str,ptr) (int)_Fgpos(str,ptr)
#define fseek(str,off,way) _Fspos(str,_NULL,off,way)
#define fsetpos(str,ptr) _Fspos(str,ptr,0L,0)
#define ftell(str) _Fgpos(str,_NULL)
#define getc(str) ((str)->_Next < (str)->_Rend \
? *(str)->_Next++:(getc)(str))

#define getchar() (_Files[0]->_Next < _Files[0]->_Rend \
? *_Files[0]->_Next++ : (getc)(str))

#define putc(c,str) ((str)->_Next < (str)->_Wend \
?(*(str)->_Next++ = c) : (putc)(c,str))

#define putchar(c) (_Files[1]->_Next < _Files[1]->_Wend \
? (*_Files[1]->_Next++ = c):(putchar)(c))

#endif

 


int (fclose)(FILE *str){
int stat = fflush(str);

if(str->_Mode & _MALBUF)
free(str->_Buf);
str->_Buf = NULL;
if(0 <= str->_Handle && _Fclose(str))
stat = EOF;
if(str->_Tmpnam){
if(remove(str->_Tmpnam))
stat = EOF;
free(str->_Tmpnam);
str->_Tmpnam = NULL;
}

str->_Mode = 0;
str->_Next = &str->_Cbuf;
str->_Rend = &str->_Cbuf;
str->_Wend = &str->_Cbuf;
str->_Nback = 0;

&nbsp;

if(str->_Mode & _MALFIL)
{
size_t i;

for(i = 0; i < FOPEN_MAX;++i)
if(_Files[i] == str){
_Files[i] = NULL:
break;
}
free(str);
}
return (stat);
}

 


FILE *(fopen)(const char *name,const char *mods)
{
FILE *str; //首先FILE 指针
size_t i;

for(i = 0; i < FOPEN_MAX;++i){ //查找还有没有可以打开的文件数目
if(_Files[i] == NULL){
str = malloc(sizeof(FILE));
if(str == NULL)
return NULL;

_Files[i] = str;
str->_Mode = _MALFIL;
break;
}else if(_Files[i]->_Mode == 0){
str = _Files[i];
break;
}
if(FOPEN_MAX <= i)
return NULL;
return (_Foprep(name,mods,str));

&nbsp;

}
}

&nbsp;

 

其他的可以参考我的githup  :  zmr961006

本文固定链接: http://zmrlinux.com/2015/12/01/%e6%8e%a2%e7%a7%98stdio-h-%e5%ae%9e%e7%8e%b0%e4%b8%8e%e4%bd%bf%e7%94%a8/ | Kernel & Me

该日志由 root 于2015年12月01日发表在 C, C/C++ 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 探秘stdio.h 实现与使用 | Kernel & Me
【上一篇】
【下一篇】