文档章节

C程序设计语言--第八章:UNIX系统接口

fzyz_sb
 fzyz_sb
发布于 2013/10/03 15:59
字数 1791
阅读 75
收藏 2

UNIX操作系统通过一系列的系统调用提供服务,这些系统调用实际上是操作系统内的函数,它们可以被用户程序调用.

8.1 文件描述符

在UNIX操作系统中,所有的外围设备(包括键盘和显示器)都被看作是文件系统中的文件,因此,所有的输入/输出都要通过读文件或写文件完成.也就是说,通过一个单一的接口就可以处理外围设备和程序之间的所有通信.

通常情况下,在读或写文件之前,必须先将这个意图通知系统,该过程称为打开文件.系统检查你的权利(该文件是否存在?是否有访问它的权限?),如果一切正常,操作系统将向程序返回一个小的非负整数,该整数称为文件描述符.任何时候对文件的输入/输出都是通过文件描述符标识文件,而不是通过文件名标识文件.系统负责维护已打开文件的所有信息,用户程序只能通过文件描述符引用文件.

因为大多数的输入/输出是通过键盘和显示器来实现的.为了方便起见,UNIX对此作了特别的安排.当命令解释程序(shell)运行一个程序的时候,它将打开3个文件,对应的文件描述符分别是0,1,2,依次标识标准输入,标准输出和标准错误.如果程序从文件0中读,对1和2进行写,就可以进行输入/输出而不必关心打开文件的问题.

程序的使用者可以通过<和>重定向程序的I/O.

prog < infile > outfile
8.2 低级I/O----read和write
int n_read = read( int fd, char *buf, int n );
int n_written = write( int fd, char *buf, int n );
这两个函数中,第一个参数是文件描述符,第二个参数是程序中存放读或写的数据的字符数组,第三个参数是要传输的字节数.每次调用返回实际传输的字节数.在读文件时,函数的返回值如果为0,则表示已到达文件的末尾;如果返回值为-1,则表示发生了某种错误.在写文件时,返回值是实际写入的字节数.如果返回值与请求写入的字节数不相等,则说明发生了错误.

通过read和write来写一个输入复制到输出的程序:

#include <stdio.h>

#define BUFSIZE 20
int main( void )
{
	char buf[ BUFSIZE ];
	int n;
	memset( buf, 0, BUFSIZE );

	while ( ( n = read( 0, buf, BUFSIZE ) ) > 0 ){
		write( 1, buf, BUFSIZE );
	}

	return 0;
}
之所以成为低级I/O,是因为上面的程序会老老实实的读取BUFSIZE,无论你输入的是多少.例如:

所以,一般情况下写程序是不会用到read和write的.

而getchar则可以通过read来实现:

1. 无缓冲的单字符输入

int getchar( void )
{
	char c;
	return ( read( 0, &c, 1 ) == 1 ) ? ( unsigned char ) c : EOF;
}
其中,c必须是一个char类型的变量,因为read函数需要一个字符指针类型的参数(&c).在返回语句中将c转换为unsigned char类型可以消除符号扩展问题.

2. 简单的带缓冲区的版本

#define BUFSIZE 128

int getchar( void )
{
	static char buf[ BUFSIZE ];
	static char *bufp = buf;
	static int n = 0;

	if ( n == 0 ){
		n = read( 0, buf, sizeof( buf ) );
		bufp = buf;
	}
	return ( --n >= 0 ) ? ( unsigned char ) *bufp++ : EOF;
}
可能有些人会问程序中bufp的作用是什么,为什么不能直接用buf.细心的会发现,如果用buf,则*bufp++需要改为buf[ i++ ],需要引入一个static int i.这就是指针的魅力所在.

8.3 open,creat,close和unlink

除了默认的标准输入,标准输出和标准错误文件外,其他文件都必须在读或写之前显式的打开.系统调用open和creat用于实现该功能.

open返回一个文件描述符,如果发生错误,open将返回-1.

#include <fcntl.h>
int fd;
int open( char *name, int flags, int perms );
fd = open( name, flags, perms );
参数name是一个包含文件名的字符串,flags是一个int类型的值,它说明以何种方式打开文件:
O_RDONLY	只读方式
O_WRONLY	只写方式
O_RDWR		读写方式
perms代表权限.

就目前的UNIX系统中,creat的方法已经不推荐使用了.之前之所以存在是因为用open打开一个不存在的文件会发生错误,但现在打开一个不存在的文件时候,会自动创建这个文件.

我们来编写一个简化版的UNIX程序cp:

#include <stdio.h>
#include <fcntl.h>
#include <stdarg.h>
#define PERMS 0666
#define BUFSIZE 128

void error( char *, ... );

int main( int argc, char *argv[] )
{
	int f1, f2, n;
	char buf[ BUFSIZE ];

	if (argc != 3 ){
		error("usage:cp from to ");
	}
	if ( ( f1 = open( argv[ 1 ], O_RDONLY, 0 ) ) == -1 ){
		error("cp:can't open %s", argv[ 1 ] );
	}
	if ( ( f2 = creat( argv[ 2 ], PERMS ) ) == -1 ){
		error("cp:can't create %s, mode %03o", argv[ 2 ], PERMS );
	}

	while ( ( n = read( f1, buf, BUFSIZE ) ) > 0 ){
		if ( write( f2, buf, n ) != n ){
			error("cp: write error on file %s", argv[ 2 ] );
		}
	}

	return 0;
}

void error( char *fmt, ... )
{
	va_list args;

	va_start( args, fmt );
	fprintf(stderr, "error: ");
	vfprintf( stderr, fmt, args );
	fprintf( stderr, "\n" );
	va_end( args );
	exit( 1 );
}
函数unlink( char *name )将文件name从文件系统中删除,它对应于标准库函数remove.

习题8-1:

#include <stdio.h>
#include <fcntl.h>
#include <stdarg.h>
#define BUFSIZE 128

void error( char *, ... );

int main( int argc, char *argv[] )
{
	int fd;
	void filecopy( int ifd, int ofd );

	if ( argc == 1 ){
		filecopy( 0, 1 );
	}
	else{
		while ( --argc > 0 ){
			if ( ( fd = open( *++argv, O_RDONLY ) ) == -1 ){
				error("cat: can't open %s", *argv );
			}
			else{
				filecopy( fd, 1 );
				close( fd );
			}
		}
	}

	return 0;
}

void filecopy( int ifd, int ofd )
{
	int n;
	char buf[ BUFSIZE ];

	while ( ( n = read( ifd, buf, BUFSIZE ) ) > 0 ){
		if ( write( ofd, buf, n ) != n ){
			error( "cat: write error" );
		}
	}
}

void error( char *fmt, ... )
{
	va_list args;

	va_start( args, fmt );
	fprintf(stderr, "error: ");
	vfprintf( stderr, fmt, args );
	fprintf( stderr, "\n" );
	va_end( args );
	exit( 1 );
}
8.4 随机访问----lseek

输入/输出通常是顺序进行的:每次调用read和write进行读写的位置紧跟在前一次操作的位置之后.但是,有时候需要以任意顺序访问文件,系统调用lseek可以在文件中任意移动位置而不是及读写任何数据:

long lseek( int fd, long offset, int origin );
将文件描述符为fd的文件的当前位置设置为offset,其中,offset是相对于origin指定的位置而言.origin的值可以为0,1或2,分别用于指定offset从文件开始,从但钱位置或从文件结束处开始算起.

使用lseek系统调用时,可以将文件视为一个大数组,其代价是访问速度会慢一些.下面的函数将从文件的任意位置读入任意数目的字节,它返回读入的字节数,若发生错误,则返回-1:

int get( int fd, long pos, char *buf, int n )
{
	if ( lseek( fd, pos, 0 ) >= 0 ){
		return read( fd, buf, n );
	}
	else{
		return -1;
	}
}

由于对UNIX不太熟悉,所以8.5,8.6,8.7看得不太懂,故无法做任何的笔记.先放着.

等对C语言有了进一步的认识后,再回头看看K&R的第五章,第六章和第八章.这三章所讲的内容实在是太丰富了.


© 著作权归作者所有

共有 人打赏支持
fzyz_sb
粉丝 408
博文 209
码字总数 447144
作品 0
武汉
程序员
计算机书籍目录

计算机系统与网络 《图灵的秘密》 《计算机系统概论》 《深入理解Linux内核》 《深入Linux内核架构》 《TCP/IP详解 卷1:协议》 《Linux系统编程(第2版)》 《Linux内核设计与实现(第3版)...

Reborn-D
2016/11/01
24
0
【flex&bison翻译】前言

译者注:去年的时候曾经计划翻译本书,后来终于还是抵不过懒惰,给放下了,有句经典的话:现在的努力,是为了小时候吹过的牛逼。现在体会深刻啊。。。本文是在Ubuntu 12.04.1系统下,使用Lib...

MatthewChie
2012/08/25
0
2
史上最全面的C语言的学习路线及方法

UNIX下C语言的学习路线。 工具篇 “公欲善其事,必先利其器”。编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工...

stone15165
04/18
0
0
如何学好C语言?为什么会有学的既不深,也不扎实,半吊子的感觉

如何学好C语言?为什么会有学的既不深,也不扎实,半吊子的感觉 C/C++学习,解答,技术内容更多尽在:C/C++学习群:99816772 我相信,这可能是很多朋友的问题,我以前也有这样的感觉,编程编...

这个人很懒什么都没留下
2017/12/20
0
0
shell是什么语言?shell 语言的本质

shell是什么语言?shell 语言的本质 “Shell是Linux/Unix的一个外壳,你理解成衣服也行。它负责外界与Linux内核的交互,接收用户或其他应用程序的命令,然后把这些命令转化成内核能理解的语言...

dhb_oschina
2016/04/27
656
0

没有更多内容

加载失败,请刷新页面

加载更多

Univalsal_ImageLoader源码结构与创建者模式 初步小结

最近在回归看Univalsal_ImageLoader源码,本想自己也实现试试写一个,看源码是为了学习看能否使用,助于自己可以写出有自己逻辑结构的代码。 首先我们初始化ImageLoader的配置初始化的时候,...

DannyCoder
45分钟前
0
0
计算卷积神经网络浮点数运算量

前言 本文主要是介绍了,给定一个卷积神经网络的配置之后,如何大概估算它的浮点数运算量。 相关代码:CalFlops,基于MXNet框架的 Scala 接口实现的一个计算MXNet网络模型运算量的demo。 正文...

Ldpe2G
今天
3
0
Sql语言与MySql数据库

1. 数据库简介 1. 数据库,就是存储数据的仓库,只能通过sql语言来访问,数据库也是一个文件系统。通常,MySQL、Oracle等数据库,也被称为关系型数据库,其保存的不仅仅只是数据,还包括数据...

江左煤郎
今天
3
0
IDEA 取消自动import .*

打开设置 > Editor > Code Style > Java > Scheme Default > Imports ① 将 Class count to use import with "*" 改为 99 (导入同一个包的类超过这个数值自动变为 * ) ② 将 Names count ......

乔老哥
今天
4
0
PostGIS学习笔记(开篇)

PostGIS事实上算是笔者开始写博客的第一篇内容。而事实上那篇博文的内容并不丰富,笔者对PostGIS的了解仍然不多,然而17年在OSGeo课程学习时对PostGIS又有了进一步了解,并逐步发现它的强大。...

胖胖雕
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部