APUE第三章3.2习题分析
来源:互联网 发布:苹果录屏用什么软件 编辑:程序博客网 时间:2024/04/30 03:25
题目描述:编写一个与3.12节中dup2功能相同的函数,要求不能调用fcntl函数,并且有正确的出错处理。
题目分析:既然不能使用fcntl函数,那么我们就需要使用其他函数来达到类似的目的,这里列举出所有我们需要使用的函数。
1、 open函数:这里我们不应该指定一个文件描述符并尝试复制它,因为实际中我们不能知道我们指定的文件描述符就一定是合法的,这个文件描述符可能未被使用,如果这样的话就会导致后面一系列的操作失败。或者是这个文件描述符指向了一个已经打开,而且对用户非常重要的文件(操作不当的后果可想而知)。所以用open函数打开一个已经存在的文件是非常靠谱的,我们就可以复制open函数返回的文件描述符。当然,我们还要注意open函数调用时可能产生的错误进行处理。
2、 dup函数:在不能使用fcntl函数的情况下,dup函数是唯一的选择。注意dup函数的返回值,如果操作成功时返回可用的最小的文件描述符,出错时返回-1。当然,dup函数出错也是有可能的,比如说系统资源问题,或者是文件描述符用光(就现在的UNIX Like来说貌似不大可能,但是还是建议考虑一下)。
3、 输出函数:你需要将一些错误的信息输出到屏幕,告诉用户相关的错信息。
4、 close函数:用来关闭一个文件描述符,如果我们指定了将文件描述符a复制为b,如果文件描述符b被占用了,那么我们应该立即关闭它。
5、 atoi函数:将字符串转成数字,这个函数有可能会用到,具体需要看程序是如何实现的。
思路与实现细节:
首先我们应该用open函数打开一个文件,并获取open函数返回的文件描述符,我们假定open函数获取的文件描述符为”file_flag”,要复制成的文件描述符为”obj_flag”。我们要考虑下面的一些问题,比如说打开文件操作失败,文件访问权限问题或者文件不存在都会导致该问题。当然,这似乎不应该是这个程序需要重点处理的问题,我们只需要返回一个适当的错误信息就可以了,不必去进行创建文件的操作。想一想,一个程序在悄无声息的就创建了一个用户以为存在(实际原来不存在)的文件而且还对其进行了操作。当然用户可能认为这些过程都是正确的(比如那个文件原来就存在),后果有可能是难以预测的。另外,通过open函数获取的文件描述符(file_flag)很可能与你指定要复制成的文件描述符(obj_flag)相同!这就涉及到了下一个问题,我们指定的文件描述符是否合法。
指定的文件描述符不应该占用0~2这三个文件描述符,而且不能超过一个系统允许的上限,即OPEN_MAX,不过有些UNIX Like对其没有限制,但是建议指定的文件描述符不要过大。如果指定的文件描述符与open函数获取的文件描述符相同当然也是不行的。如果出现文件描述符上述三种问题,应该返回错误,或者干脆让用户重新指定文件描述符。
实现dup2函数的方式并不难,我们先要保证文件描述符3到obj_flag都被占满,这个只需要不断地调用函数:”dup(file_flag)”,直到其返回的文件描述符值不小于obj_flag。同时需要将这些通过dup函数得到的文件描述符记录下来,以便于以后的释放。之后我们调用函数”close(obj_flag)”,这样就保证了小于obj_flag的所有文件描述符都被占用,而文件描述符obj_flag是可用的。接下来调用”dup(file_flag)”就可以保证了返回的文件描述值为obj_flag(为严谨起见我们还是应该对此时dup函数的返回值进行判断)。如此就实现了与dup2函数相似的功能,但是不要忘记释放那些额外占用的文件描述符,我们需要及时的将其释放。否则如果该程序进程为关闭,就可能在某些UNIX Like系统上造成文件描述符不够用的情况。使用dup函数时,我们也要考虑是否可能存在着dup函数返回一个错误的情况,这时返回一个错误并输出一些相关的警告应该就可以OK了。
这道题的思路大致如此。当然,即使是上面所有情况都考虑到了这个实现也没有足够好。因为这毕竟不是一个原子操作,如果有另外的一个进程对打开文件操作的话,上面思路实现的代码可靠性仍然没有保证。
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int fd = -1;
fd = mydup2(0,10);
if(fd < 0)
{
perror("mydup2");
return -1;
}
printf("fd = %d\n",fd);
return 0;
}
int mydup2(int fd, int newfd)
{
//判断fd和newfd的范围是否正确
if(fd < 0 || fd > 256)
{
printf("fd is wrong.\n");
return -1;
}
if(newfd <0 || newfd > 256)
{
printf("newfd is wrong.\n");
return -1;
}
int index = 0;
int fdarray[newfd];
//判断fd是否已经被打开。
if((fdarray[index] = dup(fd)) == -1)
{
printf("error while dup.\n");
return -1;
}
else
{
close(fdarray[index]);
}
//如果相等,则直接返回。
if(fd == newfd)
{
return newfd;
}
//将newfd关闭
close(newfd);
//获取所要的newfd
int newfdindex;
for(index=0; index<=newfd; index++)
{
fdarray[index] = dup(fd);
if(fdarray[index] == -1)
{
printf("error while dup.\n");
return -1;
}
else
{
if(fdarray[index] == newfd)
{
newfdindex = index;
break;
}
}
}
//将之前打开的fd都关闭
for(index=0; index<newfdindex; index++)
{
close(fdarray[index]);
}
return fdarray[newfdindex];
}
- APUE第三章3.2习题分析
- [APUE] 第三章部分习题
- apue第三章习题3.2 编写dup2功能相同的函数,要求不调用fcntl函数
- 《APUE》第三章笔记(4)及习题3-2
- APUE 2 - 第三章文件I/O学习-习题
- APUE习题3.2/3.6
- [APUE] 第四章习题解答
- APUE-第四章-习题笔记
- APUE第三章
- APUE 第三章
- Apue第三章
- apue第三章(1)
- apue第三章(2)
- APUE 学习笔记(第三章)
- APUE第三章 文件IO
- APUE第三章学习笔记
- APUE第三章 文件IO
- 数据结构与算法分析课后习题第三章(2)
- ANDROID内存优化(大汇总——全)
- 使用PageHeap.EXE或GFlags.EXE检查内存越界错误(转)
- onSaveInstanceState执行时机
- java中異常(一)
- 基础算法系列(十九)排序算法之内省排序
- APUE第三章3.2习题分析
- win 7和Ubuntu 14.04双系统安装与卸载
- 安装使用protobuf,及使用C++编写多线程通信
- StageFright框架(三)選擇Video Decoder
- RSA MD5 加密
- QR Code reader
- HR学习笔记2
- response.setContentType()的作用参数详解
- 电长度 和物理长度