最近,在看《深入理解计算机系统》,在看到虚拟存储器这一章节时,遇到一个习题:

编写一个C程序mmapcopy.c, 使用mmap将一个任意大小的磁盘文件拷贝到stdout。输出文件的名字必须作为一个命令行参数来传递。

google了一下,下面附上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main (int argc, char *argv[])
{
struct stat sb;
off_t len;
char *p;
int fd;
if (argc < 2) {
fprintf (stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
fd = open (argv[1], O_RDONLY);
if (fd == -1) {
perror ("open");
return 1;
}
if (fstat (fd, &sb) == -1) {
perror ("fstat");
return 1;
}
if (!S_ISREG (sb.st_mode)) {
fprintf (stderr, "%s is not a file\n", argv[1]);
return 1;
}
p = mmap (0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (p == MAP_FAILED) {
perror ("mmap");
return 1;
}
if (close (fd) == -1) {
perror ("close");
return 1;
}
for (len = 0; len < sb.st_size; len++)
putchar (p[len]);
if (munmap (p, sb.st_size) == -1) {
perror ("munmap");
return 1;
}
return 0;
}

对于这个代码,下面附上我的收获:

  • 以前写代码的时候很少考虑出错处理,在看到这段代码的时候,顿时收获良多
  • fprintf stderr的用法很重要,同时要区别与stdout的关系(区别)
  • 利用main函数进行命令行参数的传递,int main (int argc, char *argv[]),main函数 return 0 代表成功,return 非0 代表error
  • perror()用法

    函数perror()用于抛出最近的一次系统错误信息,其原型如下:
    void perror(char *string);

    说明:perror()用来将上一个函数发生错误的原因输出到标准错误(stderr)。参数string所指的字符串会先打印出,后面再加上错误原因字符串,此错误原因依照全局变量errno的值来决定要输出的字符串。

  • fstat( ) returns information about a given file
  • off_t代表文件的偏移,与size_t的区别和联系可参考stackoverflow

参考资料:

  1. safaribooksonline