当前位置:网站首页>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 执行缓冲方式的写操作
边栏推荐
- puppeteer入门之 Page 类
- Global and Chinese market for material injection 2022-2028: Research Report on technology, participants, trends, market size and share
- Golang collaboration scheduling (I): Collaboration Status
- 盒马,最能代表未来的零售
- 办公室VR黄片,骚操作!微软HoloLens之父辞职!
- Step by step to create a trial version of ABAP program containing custom screen
- acwing 801. 二进制中1的个数(位运算)
- The nohup command uses
- Difference between tinyint and int
- < 山东大学软件学院项目实训 > 渲染引擎系统——辐射预计算(九)
猜你喜欢

leetcode-54. Spiral matrix JS

2022.02.28 - SX11-05. The largest rectangle in the histogram

The common hand, the original hand and the excellent hand from the sum of Fibonacci sequence

Saga体系结构模式:微服务架构下跨服务事务的实现

Project training of Software College of Shandong University rendering engine system basic renderer (6)

Review of the development of China's medical beauty (medical beauty) industry in 2021: the supervision is becoming stricter, the market scale is expanding steadily, and the development prospect is bro

Five models of software testing

当编程纳入到高考。。。

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

Project training of Software College of Shandong University rendering engine system basic renderer (IV)
随机推荐
Project training of Software College of Shandong University rendering engine system basic renderer (6)
Global and Chinese market of vascular prostheses 2022-2028: Research Report on technology, participants, trends, market size and share
Step by step steps to create an ABAP program with a custom screen
鼻孔插灯,智商上升,风靡硅谷,3万就成
How to analyze the running time and CPU utilization of Go programs?
Scanpy (VI) analysis and visualization of spatial transcriptome data
Use of packet capturing tool Fiddler: simulating speed limit test process in weak network environment
glibc 内存管理模型 释放 C库内存缓存
C regular expression
Great God cracked the AMD k6-2+ processor 22 years ago and opened the hidden 128KB L2 cache
MySQL blob and text types
Global and Chinese market of medical ECG telemetry equipment 2022-2028: Research Report on technology, participants, trends, market size and share
nohup 命令使用
Golang collaboration scheduling (I): Collaboration Status
acwing 800. 数组元素的目标和
< 山东大学软件学院项目实训 > 渲染引擎系统——基础渲染器(四)
【工具推荐】个人本地 markdown 知识图谱软件 Obsidian
Interview: do you understand the packing and unpacking operations?
ER diagram made by StarUML based on the last student achievement management system
MYSQL---服务器配置相关问题