当前位置:网站首页>The C Programming Language(第 2 版) 笔记 / 8 UNIX 系统接口 / 8.5 实例(fopen 和 getc 函数的实现)
The C Programming Language(第 2 版) 笔记 / 8 UNIX 系统接口 / 8.5 实例(fopen 和 getc 函数的实现)
2022-06-12 16:15:00 【M菜鸟M】
8.5 实例(fopen 和 getc 函数的实现)
下面以标准库函数 fopen 和 getc 的一种实现方法为例来说明如何将这些系统调用结合起来使用
标准库中的文件不是通过文件描述符描述的,而是使用文件指针描述的
文件指针是一个指向包含文件各种信息的结构的指针,该结构包含下列内容:
- 一个指向缓冲区的指针,通过它可以一次读入文件的一大块内容
- 一个记录缓冲区中剩余的字符数的计数器
- 一个指向缓冲区中下一个字符的指针
- 文件描述符
- 描述读/写模式的标志
- 描述错误状态的标志
- 其它
描述文件的数据结构包含在头文件 <stdio.h> 中
任何需要使用标准输入/输出库中函数的程序都必须在源文件中包含这个头文件(通过 #include 指令包含头文件)
此文件也被库中的其它函数包含
在下面这段典型的 <stdio.h> 代码段中,只供标准库中其它函数所使用的名字以下划线开始,因此一般不会与用户程序中的名字冲突
所有的标准库函数都遵循该约定
#define NULL 0
#define EOF (-1)
#define BUFSIZ 1024
#define OPEN_MAX 20 /* max #files open at once */
typedef struct _iobuf {
int cnt; /* characters left */
char *ptr; /* next character position */
char *base; /* location of buffer */
int flag; /* mode of file access */
int fd; /* file descriptor */
} FILE;
extern FILE _iob[OPEN_MAX];
#define stdin (&_iob[0])
#define stdout (&_iob[1])
#define stderr (&_iob[2])
enum _flags {
_READ = 01, /* file open for reading */
_WRITE = 02, /* file open for writing */
_UNBUF = 04, /* file is unbuffered */
_EOF = 010, /* EOF has occurred on this file */
_ERR = 020 /* error occurred on this file */
};
int _fillbuf(FILE *);
int _flushbuf(int, FILE *);
#define feof(p) ((p)->flag & _EOF) != 0)
#define ferror(p) ((p)->flag & _ERR) != 0)
#define fileno(p) ((p)->fd)
#define getc(p) (--(p)->cnt >= 0 \
? (unsigned char) *(p)->ptr++ : _fillbuf(p))
#define putc(x,p) (--(p)->cnt >= 0 \
? *(p)->ptr++ = (x) : _flushbuf((x),p))
#define getchar() getc(stdin)
#define putchar(x) putc((x), stdout)
宏 getc 一般先将计数器减 1,将指针移到下一个位置,然后返回字符
一个长 #define 语句可用反斜杠分成几行
如果计数值变为负值,getc 就调用函数 _fillbuf 填充缓冲区,重新初始化结构的内容,并返回一个字符
返回的字符为 unsigned 类型,以确保所有的字符为正值
尽管在这里我们并不想讨论一些细节,但程序中还是给出了 putc 函数的定义,以表明它的操作与 getc 函数非常类似
当缓冲区满时,它将调用函数 _flushbuf
此外,我们还在其中包含了访问错误输出、文件结束状态和文件描述符的宏
fopen 函数的主要功能是打开文件,定位到合适的位置,设置标志位以指示相应的状态
它不分配任何缓冲区空间,缓冲区的分配是在第一次读文件时由函数 _fillbuf 完成的
#include <fcntl.h>
#include "syscalls.h"
#define PERMS 0666 /* RW for owner, group, others */
FILE *fopen(char *name, char *mode)
{
int fd;
FILE *fp;
if (*mode != 'r' && *mode != 'w' && *mode != 'a')
return NULL;
for (fp = _iob; fp < _iob + OPEN_MAX; fp++)
if ((fp->flag & (_READ | _WRITE)) == 0)
break; /* found free slot */
if (fp >= _iob + OPEN_MAX) /* no free slots */
return NULL;
if (*mode == 'w')
fd = creat(name, PERMS);
else if (*mode == 'a') {
if ((fd = open(name, O_WRONLY, 0)) == -1)
fd = creat(name, PERMS);
lseek(fd, 0L, 2);
} else
fd = open(name, O_RDONLY, 0);
if (fd == -1) /* couldn't access name */
return NULL;
fp->fd = fd;
fp->cnt = 0;
fp->base = NULL;
fp->flag = (*mode == 'r') ? _READ : _WRITE;
return fp;
}
该版本的 fopen 函数没有涉及标准 C 的所有访问模式,但是,加入这些模式并不需要增加多少代码
特别是,该版本的 fopen 不能识别表示二进制访问方式的 b 标志,这是因为,在 UNIX 系统中这种方式是没有意义的
同时,它也不能识别允许同时进行读和写的 + 标志
对于某一特定的文件,第一次调用 getc 函数时计数值为 0,这样就必须调用一次函数 _fillbuf
如果 _fillbuf 发现文件不是以读方式打开的,它将立即返回 EOF
否则,它将试图分配一个缓冲区(如果读操作是以缓冲方式进行的话)
建立缓冲区后,_fillbuf 调用 read 填充此缓冲区,设置计数值和指针,并返回缓冲区中的第一个字符
随后进行的 _fillbuf 调用会发现缓冲区已经分配
#include "syscalls.h"
/* _fillbuf: allocate and fill input buffer */
int _fillbuf(FILE *fp)
{
int bufsize;
if ((fp->flag&(_READ|_EOF_ERR)) != _READ)
return EOF;
bufsize = (fp->flag & _UNBUF) ? 1 : BUFSIZ;
if (fp->base == NULL) /* no buffer yet */
if ((fp->base = (char *) malloc(bufsize)) == NULL)
return EOF; /* can't get buffer */
fp->ptr = fp->base;
fp->cnt = read(fp->fd, fp->ptr, bufsize);
if (--fp->cnt < 0) {
if (fp->cnt == -1)
fp->flag |= _EOF;
else
fp->flag |= _ERR;
fp->cnt = 0;
return EOF;
}
return (unsigned char) *fp->ptr++;
}
必须先定义和初始化数组 _iob 中的 stdin、stdout 和 stderr 值:
FILE _iob[OPEN_MAX] = {
/* stdin, stdout, stderr */
{
0, (char *) 0, (char *) 0, _READ, 0 },
{
0, (char *) 0, (char *) 0, _WRITE, 1 },
{
0, (char *) 0, (char *) 0, _WRITE, | _UNBUF, 2 }
};
该结构中 flag 部分的初值表明,将对 stdin 执行读操作、对 stdout 执行写操作、对 stderr 执行缓冲方式的写操作
边栏推荐
- acwing 802. 区间和 (离散化)
- Project training of Software College of Shandong University rendering engine system radiation pre calculation (VIII)
- puppeteer入门之 Page 类
- From K-means to capsule
- Reprise de Google net
- Decision tree classification and examples
- Unity get local video / download network video
- 一步步创建包含自定义 Screen 的 ABAP 程序的详细步骤
- acwing795 前缀和(一维)
- d的sha6转大整
猜你喜欢
![In 2020, the demand for strain sensors in China will reach 9.006 million, and the market scale will reach 2.292 billion yuan [figure]](/img/a8/dd5f79262fe6196dd44ba416a4baac.jpg)
In 2020, the demand for strain sensors in China will reach 9.006 million, and the market scale will reach 2.292 billion yuan [figure]

Why doesn't Alibaba recommend MySQL use the text type?

Project training of Software College of Shandong University rendering engine system basic renderer (V)
![Analysis of China's cargo transport volume, cargo transport turnover and port cargo in 2021 [figure]](/img/ee/ae9984355a98f5529dd4574eea2e7c.jpg)
Analysis of China's cargo transport volume, cargo transport turnover and port cargo in 2021 [figure]

Huawei equipment is configured with CE dual attribution

Defer learning in golang

Introduction and download website of common data of GIS, remote sensing, hydrology and Geography (2), supplementary~

Use of packet capturing tool Fiddler: simulating speed limit test process in weak network environment

acwing788. 逆序对的数量

Let's talk about events. Listen to those things. - Part one
随机推荐
Analysis of global and Chinese shipbuilding market in 2021: the global shipbuilding new orders reached 119.85 million dwt, with China, Japan and South Korea accounting for 96.58%[figure]
[tool recommendation] personal local markdown knowledge map software
tinyint和int区别
Learning record [email protected] understand canvas
【周赛复盘】LeetCode第80场双周赛
[weekly replay] game 80 of leetcode
位运算例题(待续)
思考游戏王决斗链接中抽卡概率问题
【工具推荐】个人本地 markdown 知识图谱软件 Obsidian
Kill program errors in the cradle with spotbugs
UE4 common type conversion
redis 通用命令
Global and Chinese market of soft capsule manufacturing equipment 2022-2028: Research Report on technology, participants, trends, market size and share
面试:为什么整数包装类尽量用equals()来比较大小
Super detailed dry goods! Docker+pxc+haproxy build a MySQL Cluster with high availability and strong consistency
< 山东大学软件学院项目实训 > 渲染引擎系统——辐射预计算(八)
acwing 2816. 判断子序列
一步步创建包含自定义 Screen 的 ABAP 程序的详细步骤
[automation] kolla Based Automated Deployment CEPH cluster
glibc 内存管理模型 释放 C库内存缓存