UNIX环境高级编程:第三章课后习题

1,当读写磁盘文件时,read,write等函数确实是不带缓冲机制的吗?请说明原因。

  答:所有磁盘I/O都要经过内核的块缓存区(即内核的缓冲区高速缓存)。唯一例外的是对原始磁盘设备的I/O,但是我们不考虑这种情况。既然read或write的数据都要被内核缓冲,那么术语“不带缓冲的I/O”指的是在用户的进程中对这两个函数不会自动缓冲,每次read或write就要进行一次系统调用。

2,编写一个与dup2功能相同的函数,要求不调用fcntl函数,并且要有正确的出错处理。

#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>

#define    OPEN_MAX_GUESS    256

long
open_max(void)  //这里是第二章的习题代码
{
    long openmax;
    struct rlimit rl;

    if ((openmax = sysconf(_SC_OPEN_MAX)) < 0 || openmax == LONG_MAX) 
    {
        if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
            perror("can't get file limit");
        if (rl.rlim_max == RLIM_INFINITY)
            openmax = OPEN_MAX_GUESS;
        else
            openmax = rl.rlim_max;
    }
    return(openmax);
}

int my_dup2(int oldfd, int newfd)
{
    int fd;
    int begin_fd;
    long t_openmax;
    int i;
    t_openmax = open_max();
    printf("open_max is %ld\n", t_openmax);
    if(oldfd < 0 || newfd < 0 || oldfd > (t_openmax - 1) || newfd > (t_openmax - 1))  //以当前系统最大打开文件数量为限
    {
        perror("fd error");
        return -1;
    }
    
    if(oldfd == newfd)
    {
        return newfd;
    }
    close(newfd);
    fd = dup(oldfd);
    begin_fd = fd;
    while(fd < (t_openmax - 1))  //循环对比当前复制的文件描述符是否符号要求
    {
        if(fd == newfd) 
        {
            printf("get newfd\n");
            break;
        }
        fd = dup(oldfd);
        if(fd == -1) 
        {
            perror("dup error");
            return -1;
        }
        
    }
    for(i = begin_fd;i < fd; i++)
    {
       close(i);
    }  
    return fd;
}

int main(int argc, char *argv[])
{
    int oldfd;
    int newfd;
    
    char *buf="This is my_dup2 test\n";
    
    if((oldfd = open("my_dup2_text.txt",O_RDWR|O_CREAT,0644)) == -1)
    {
        perror("my_dup2_text open error");
        exit(-1);
    }
    newfd = my_dup2(oldfd, 1023);
    if(newfd == -1)
    {
        perror("my_dup2 error");
        exit(-1);      
    }
    printf("newfd is %d\n", newfd);
    if(write(newfd, buf, strlen(buf)) != strlen(buf))
    {
        perror("write error");
        exit(-1);         
    }
    
    close(newfd);
    exit(0);
}

3,假设一个进程执行下面3个函数调用:

fd1 = open(path, oflags);
fd2 = dup(fd1);
fd3 = open(path, oflags);

  指出三个文件描述符的文件表关系。对fcntl作用于fd1来说,F_SETFD命令会影响哪一个文件描述符?F_SETEL呢?

答:fd1、fd2指向同一个文件表,fd3有新的文件表,但是v节点表与fd1、fd2一样。F_SETFD只影响fd1,因为这个标志位的作用是设置文件描述符。F_SETEL影响fd1和fd2,因为它设置的是文件的状态。

 

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

dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
if (fd > 2)
    close(fd);

  为了说明if语句的必要性,假设fd是1,画出每次调用dup2时3个描述符及相应的文件表项的变化情况。然后再画出fd为3的情况。

  答:fd为1的情况:fd标志为0、2、1都指向同样的文件表。

  fd为3的情况:fd标志为0、1、2、4都指向同样的文件表。

  因为 0、1、2分别对应stdin, stdout, stderr,是不应该关闭的,这段程序的目的是把stdin, stdout, stderr这三个标准fd重定向到同一个文件描述符里,当fd大于2时,因为目的已经达成,大于2的fd已经不需要了,为了避免造成浪费,所以关闭它。

5,在bourne shell、Bourne-again shell和Korn shell中,digit1>&digit2表示要将描述符digit1重定向至描述符digit2的同一文件。请说明下面两条命令的区别。

./a.out > outfile 2>&1
./a.out 2>&1 > outfile

  答:第一条是把标准错误和标准输出都重定向到outfile,指向同一文件表项;

    第二条是标准错误重定向到标准输出,然后标准输出又重定向到outfile,所以标准输出指向outfile的文件表项,标准错误指向终端的文件表项,所有标准错误都会打印到终端。

6,如果使用追加标志打开一个文件以便读、写,能否仍用lseek在任一位置开始读?能否用lseek更新文件中任一部分的数据?请编写一段程序验证。

定义函数:

1

off_t lseek(int fildes, off_t offset, int whence);

函数说明:
每一个已打开的文件都有一个读写位置, 当打开文件时通常其读写位置是指向文件开头, 若是以附加的方式打开文件(如O_APPEND), 则读写位置会指向文件尾. 当read()或write()时, 读写位置会随之增加,lseek()便是用来控制该文件的读写位置. 参数fildes 为已打开的文件描述词, 参数offset 为根据参数whence来移动读写位置的位移数.

参数 whence 为下列其中一种:

  •     SEEK_SET 参数offset 即为新的读写位置.
  •     SEEK_CUR 以目前的读写位置往后增加offset 个位移量.
  •     SEEK_END 将读写位置指向文件尾后再增加offset 个位移量. 当whence 值为SEEK_CUR 或
  •     SEEK_END 时, 参数offet 允许负值的出现.

下列是教特别的使用方式:
1) 欲将读写位置移到文件开头时:lseek(int fildes, 0, SEEK_SET);
2) 欲将读写位置移到文件尾时:lseek(int fildes, 0, SEEK_END);
3) 想要取得目前文件位置时:lseek(int fildes, 0, SEEK_CUR);

 

  答:能在任一位置开始读,但不能更新任一部分的数据,只能追加,程序如下:

#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
    int fd;
   
    char buf_read[10];
    char *buf="This is lseek test\n";
   
    if((fd = open("lseek.txt",O_RDWR|O_CREAT|O_APPEND,0644)) == -1)
    {
        perror("fd open error");
        exit(-1);
    }
   
    if(write(fd, buf, strlen(buf)) != strlen(buf))
    {
        perror("write error");
        exit(-1);        
    }
    lseek(fd, 2, SEEK_SET);
    read(fd, buf_read, 10);
    lseek(fd, 2, SEEK_SET);
    printf("lseek read is: %s\n", buf_read);
    if(write(fd, buf, strlen(buf)) != strlen(buf))
    {
        perror("write error");
        exit(-1);        
    }
    close(fd);
    exit(0);
}

运行结果如下:

dog@dog:~/test$ ./a.out
lseek read is: is is lsee
dog@dog:~/test$ cat lseek.txt
This is lseek test
This is lseek test

 

 

 

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值