admin 管理员组

文章数量: 1086019


2024年3月13日发(作者:termux工作目录)

UNX环境高级编程第三章课后习题解析

3.1

当读

/

写磁盘文件时,本章中描述的函数是否有缓冲机制?请说明原因。

解析:

write

这两个系统调用。这两个函数由于是系本章中的函数应该是特指

read

统调用,因此这两个函数都是在内核中进行,所以称之为不带缓冲的

I/O

函数。

而带有缓冲的函数本质上是依赖一段额外的内存空间作为临时缓冲区,这样做可

以避免一些不当的设置导致读写性能较低的问题,例如标准

I/O

函数中的

gets

等函数大致就是这样的。很显然,系统调用

read

write

并没有借助这样的技术。

3.2

编写一个与

3.12

节中

dup2

功能相同的函数,要求不调用

fcntl

函数,并且

要有正确的出错处理。

解析:

既然不能够使用

fcntl

函数,那么我们实现只能考虑使用

dup

函数,当然这个

实现方式相对来说非常的暴力。首先我们关闭指定的新描述符,之后我们开始暴

力的调用

dup

函数,直到

dup

函数返回值与指定的新描述符值相同为止,在这个

过程中我们要通过一个线性的结构来记录中间所有被

dup

调用打开的描述符。这

些描述符的打开并不是我们预期的,随后我们必须逐个关闭这些描述符,否则不

但会额外占用大量的系统资源,导致进程无法打开新的文件,还导致了通过其它

描述符也可以对文件进行访问,所以它们必须被关闭。

至于错误处理问题,我们就需要关心一下

errno

这个东西了,如果仅仅从

errno

入手的话,我们没有必要在一开始就检查这个指定的新描述符值是否小于系统中

的限制值,只需关心它是否为非负数就可以了,在之后的不断调用

dup

函数的过

程中,如果如果

dup

函数出现错误就直接返回

-1

就是了,这里也会包括无法在打

开更多描述符的问题,在忽视其他进程也调用类似函数的情况下这说明我们指定

的新描述符值相对来说太大了。至于

errno

值就不必关心了,这个值仅仅在函数

出现错误的时候可能会用到,而且不会在任何库函数调用前被重置。因此,当我

们自己编写的函数出错返回时,

errno

值会被保留,我们可以大概知道是在哪一

步出现了错误。

这里我们或许可以借助

sysconf

函数来获取系统对一个进程打开最大描述符

的限制,使用

sysconf

函数获取相关限制是一个很好的编程习惯,这使得代码具

有更好的移植性,详细内容请参考《

UNIX

环境高级编程》第

2.5

节。

在最后我们需要补充一点,那就是当原始描述符与新指定的描述符值相同的

情况,如果此时直接将新指定的描述符关闭的话,那么恐怕就要出现问题了,很

显然这和我们的预期并不相符。

3.3

假设一个进程执行下面的

3

个函数调用:

fd1=open(pathname,oflags);

fd2=dup(fd1);

fd3=open(pathname,oflags);

画出类似于图

3-3

的结果图。对

fcntl

作用于

fd1

来说,

F_SETFD

命令会影

响到哪个文件描述符?

F_SETFL

呢?

解析:

这道题的关键之一就是画出结果图,这一点非常重要,只要图画出来了一切

都好解释了。首先

fd2

描述符是由

fd1

描述符直接通过

dup

函数复制而来,那么

我们可以看到这两个描述符其实是共享同一个文件表的。而

fd3

则是通过

open

函数与

fd1

打开了同一个文件,不过这两个描述符是不可能共享一个文件表的,

只不过由于打开的是同一个文件,那么二者的文件表中

v

节点指针的指向是相同

的。了解这些之后结果图很容易就可以画出来了。

接下来我们要明确的是文件表中都有些什么,根据《

UNIX

环境高级编程》

的讲解,文件表中一共有三项:文件状态标志、当前文件变量和

v

节点指针。这

一点至关重要,如果不明确这点就很难得出最终的正确结论。除此之外,了解

fcntl

函数中指定

F_SETFD

F_SETFL

的作用也同样重要,

F_SETFD

作用是修改文

件描述符标志的作用,这个是仅仅对当前文件描述符起作用的,所以受影响的描

述符仅有

fd1

。而对于

F_SETFL

而言,是修改这个文件描述符打开文件的状态标

志,这个状态标志指的无非就是

O_RDONLY

之类的(详见

open

函数论述)。我

们发现这个部分居然在文件表中存储,那么我们可以断定与

fd1

共享一个文件表

的文件描述符都将会受到影响,所以此时受影响的文件描述符为

fd1

fd2

3.4

在许多程序中都包含下面一段代码:

dup2(fd,0);

dup2(fd,1);

dup2(fd,2);

if(fd>2)

close(fd);

为了说明

if

语句的必要向,假设

fd

1

,画出每次调用

dup2

3

个描述符

项及相应的文件表项的变化情况。然后画出

fd

3

的情况。

解析:

到这里相信图不再难画,如果对这个状态图仍然有疑问,那么就需要回头对

3.10

节中的内容好好研究一番了。不过问题是即使是画出图来也看不出什么问

题,感觉一切都很正常。我们很难看出调用

close

的必要性,很明显文件描述符

可以被成功复制的次数与题干中的过程没有直接关联。

这里应该是包含这一个隐含的条件,在复制完文件描述符之后,仅仅希望通

过描述符

0

1

2

进行对文件的访问。这样一来问题便能解释通了,如果是在

这样一个期望的前提下,调用

close

就有必要性了。不过我们不应该忽视的是文

件描述符

0

2

通常对应的分别是标准输入、标准输出和标准错误输出。这样做

一定是有特别用意的,我们不妨在以后的代码中注意一下这个问题。

3.5

Bourneshell

Bourne-againshell

Kornshell

中,

digit1>&digit2

示要将描述符

digit1

重定向至描述符

digit2

的同一文件。请说明下面两条命令的

区别。

./>outfile2>&1

./2>&1outfile

(提示:

shell

从左到右处理命令行)

解析:

这个就是按照命令做解释就可以了,很容易就会发现两个命令的含义完全不


本文标签: 文件 描述符 函数 打开 调用