第二章
-
2.1 We mentioned in Section 2.8 that some of the primitive system data types are defined in more than one header. For example, in FreeBSD 8.0, size_t is defined in 29 different headers. Because all 29 headers could be included in a program and because ISO C does not allow multiple typedefs for the same name, how must the headers be written?个人认为,遇到这种情况时,假设多重定义的类型为
#size_t
,那么可以采用include guard
的策略,即在头文件中,声明size_t
时,进行一次#ifndef
,#endif
的保护,从而可以避免size_t
的多重定义。 -
2.2 Examine your system’s headers and list the actual data types used to implement the primitive system data types.我的系统是macOS 10.12.6,也算是认证的Unix系统了,于是在对
<sys/types.h>
进行暗中观察😏之后,得出结论如下:typedef unsigned char u_char;typedef unsigned short u_short;typedef unsigned int u_int;#ifndef _U_LONGtypedef unsigned long u_long;#define _U_LONG#endiftypedef unsigned short ushort; /* Sys V compatibility */typedef unsigned int uint; /* Sys V compatibility */#endiftypedef u_int64_t u_quad_t; /* quads */typedef int64_t quad_t;typedef quad_t * qaddr_t;typedef char * caddr_t; /* core address */typedef int32_t daddr_t; /* disk address */typedef u_int32_t fixpt_t; /* fixed point number */typedef int32_t segsz_t; /* segment size */typedef int32_t swblk_t; /* swap offset */typedef __int32_t fd_mask;这里仅仅列出了一些基本数据类型的实现,在sys/_types
文件夹下的头文件中还有许多的其他的常见类型,如size_t
、time_t
等的实现,再此由于篇幅有限就不予详述了,总体而言,Unix下的不少以_t
结尾的类型,都是随各个系统的实现方式而可能发生变化的,具体的实现只要观察<sys/types.h>
即可得知。这个信息可以帮助我们解决一些潜在的bug。简单的介绍一些常见的unix定义的变量类型:
| 名称 | 表示数据 |
| ------------ | ------------------------------------------------------------ |
| clock_t | CPU时钟周期 |
| comp_t | 压缩后的CPU时钟周期(不属于POSIX标准) |
| dev_t | 设备编号 |
| fd_set | 文件描述符集合 |
| fpos_t | 文件位置 |
| gid_t | 用户组ID |
| ino_t | inode值(inode为一种文件系统对象,用于区分文件和文件夹等文件类型) |
| mode_t | 文件类型、文件权限 |
| nlink_t | 该目录的链接数 |
| off_t | 文件大小和偏移量 |
| pid_t | 进程ID和进程组ID |
| pthread_t | 线程ID |
| ptrdiff_t | 两个指针相减的结果 |
| rlim_t | 资源上限 |
| sig_atomic_t | 可用作信号量的原子数据类型 |
| sigset_t | 信号量集合 |
| size_t | 对象的大小(非负) |
| ssize_t | 对象的大小或-1 |
| time_t | 日历时间单位 |
| uid_t | 用户ID |
| wchar_t | 宽字符 |
-
2.3 Update the program in Figure 2.17 to avoid the needless processing that occurs when sysconf returns LONG_MAX as the limit for OPEN_MAX.Fig 2.17内容如下:#include "apue.h"#include <errno.h>#include <limits.h>#ifdef OPEN_MAXstatic long openmax = OPEN_MAX;#elsestatic long openmax = 0;#endif/** If OPEN_MAX is indeterminate, this might be inadequate.*/#define OPEN_MAX_GUESS 256longopen_max(void){if (openmax == 0) {errno = 0;/* first time through */if ((openmax = sysconf(_SC_OPEN_MAX)) < 0) {if (errno == 0)openmax = OPEN_MAX_GUESS; /* it’s indeterminate */elsefprintf(stderr, "sysconf error for _SC_OPEN_MAX");}}return(openmax);}由于实在没读懂题意,我去Google了一下,获得了如下的答案:#include "apue.h"#include <limits.h>#include <sys/resource.h>#define OPEN_MAX_GUESS 256longopen_max(void){long openmax;struct rlimit rl;if ((openmax = sysconf(_SC_OPEN_MAX)) < 0 ||openmax == LONG_MAX) {if (getrlimit(RLIMIT_NOFILE, &rl) < 0)err_sys("can't get file limit");if (rl.rlim_max == RLIM_INFINITY)openmax = OPEN_MAX_GUESS;elseopenmax = rl.rlim_max;}return(openmax);}简单的来说,如果
sysconf
函数返回了LONG_MAX
,那么这也表明OPEN_MAX
是不确定的,同时,我们可以使用geTRlimit
函数来获得每个进程最大的同时打开文件数量,从而使OPEN_MAX
成为一个合理的上限值。