前言

UNIX系统实现定义了很多幻数和常量,其中有很多已被硬编码(关于硬编码和软编码:http://www.cnblogs.com/chenkai/archive/2009/04/10/1432903.html)进程序中,或用特定的技术确定。由于大量标准化工作的努力,已有若干种可移植的方法用以确定这些幻数和实现定义的限制。这非常有助于软件的可移植性。

以下两种类型的限制是必需的:

(1)编译时限制(例如,短整型的最大值是什么?)。

(2)运行时限制(例如,文件名可以有多少个字符?)。

编译时限制可在头文件中定义,程序在编译时可以包含这些头文件。但是,运行时限制则要求进程调用一个函数以获得此种限制值。

另外,某些限制在一个给定的实现中可能是固定的(因此可以静态地在一个头文件中定义),而在另一个实现上则可能是变化的(需要一个运行时函数调用)。

为了解决这类问题,提供了以下三种限制:

(1)编译时限制(头文件)。

(2)不与文件或目录相关联的运行时限制(sysconf函数)。

(3)与文件或目录相关联的运行时限制(pathconf和fpathconf函数)。

使事情变得更复杂的是,如果一个特定的运行时限制在一个给定的系统上并不改变,则可将其静态地定义在一个头文件中。但是,如果没有将其定义在头文件中,则应用程序就必须调用三个conf函数中的一个,以确定其运行时的值。

一、ISO C 限制

ISO C定义的限制都是编译时限制。文件<limits.h>中定义的C标准限制如下:

表1 <limits.h>中定义的整型值大小

名字 说明 最小可接受值(用于16位整型系统) 典型值(32位Linux系统)
CHAR_BIT
CHAR_MAX
CHAR_MIN
SCHAR_MAX
SCHAR_MIN
UCHAR_MAX
字符的位数
字符的最大值
字符的最小值
带符号字符的最大值
带符号字符的最小值
不带符号字符的最大值

8
127
-128
127
-127
255

8
127
-128
127
-128
255

INT_MAX
INT_MIN
UINT_MAX
整型的最大值
整型的最小值
不带符号整型的最大值

32 767
-32 767
65535

2 147 483 647
-2 147 483 648
4 294 967 295

SHRT_MIN
SHRT_MAX
USHRT_MAX
短整型的最小值
短整型的最大值
不带符号短整型的最大值

-32767
32767
65535

-32768
32767
65535

LONG_MAX
LONG_MIN
ULONG_MAX
长整型的最大值
长整型的最小值
不带符号长整型的最大值

2 147 483 647
-2 147 483 647
4 294 967 295

2 147 483 647
-2 147 483 648
4 294 967 295

LLONG_MAX
LLONG_MIN
ULLONG_MAX
长长整型的最大值
长长整型的最小值
不带符号长长整型的最大值

9 223 372 036 854 775 807
-9 223 372 036 854 775 807
18 446 744 073 709 551 615

9 223 372 036 854 775 807
-9 223 372 036 854 775 808
18 446 744 073 709 551 615

MB_LEN_MAX 多字节字符常量中的最大字节数

1

16

这些常量总是定义在头文件中,而且在一个给定系统中不会改变。注意,对不带符号的数据类型都没有列出其最小值,它们都应为0。在64位系统中,其long整型的最大值与表中long long整型最大值相匹配。

我们将会遇到的一个不同之处是系统是否提供带符号或不带符号的字符集。从上表中,我们可以看到CHAR_MIN等于SCHAR_MIN,CHAR_MAX等于SCHAR_MAX;如果系统使用不带符号的字符集,则CHAR_MIN等于0,CHAR_MAX等于UCHAR_MAX。

我们会遇到的另一个ISO C常量是FOPEN_MAX,这是具体实现保证可同时打开的标准I/O流的最小数。该值在头文件<stdio.h>中定义,其值最小是8。POSIX.1中的STREAM_MAX(若定义的话)必需有与FOPEN_MAX相同的值。

ISO C在<stdio.h>中还定义了常量TMP_MAX,这是由tmpnam函数产生的唯一文件名的最大数。

表2 在各种平台上的ISO限制

限制 FreeBSD5.2.1 Linux 2.4.22 Mac OS X 10.3 Solaris 9
FOPEN_MAX
TMP_MAX

20
308 915 776

16
238 328

20
308 915 776

20
17 576

ISO C还定义了常量FILENAME_MAX,因为某些操作系统实现在历史上将它定义得太小,以至于不能满足应用的需求,所以我们应避免使用该常量。

二、POSIX限制

POSIX.1定义了很多涉及操作系统实现限制的常量,我们只关心与基本POSIX.1接口有关的部分。这些限制和常量被分成下列5类。

(1)不变的最小值:见表3。

(2)不变值:SSIZE_MAX。

(3)运行时可以增加的值:CHARCLASS_NAME_MAX、COLL_WEIGHTS_MAX、LINE_MAX、NGROUPS_MAX以及RE_DUP_MAX。

(4)运行时不变的值(可能不确定):ARG_MAX、CHILD_MAX、HOST_NAME_MAX、LOGIN_NAME_MAX、OPEN_MAX、PAGESIZE、RE_DUP_MAX、STREAM_MAXS、SYMLOOP_MAX、TTY_NAME_MAX以及TZNAME_MAX。

(5)路径名可变值(可能不确定):FILESIZEBITS、LINK_MAX、MAX_CANON、MAX_INPUT、NAME_MAX、PATH_MAX、PIPE_BUF以及SYMLINK_MAX。

表3 <limits.h>中的POSIX.1不变最小值

名字

说明:以下各项的最小可接受值

_POSIX_ARG_MAX exec函数的参数长度

4096

_POSIX_CHILD_MAX 每个实际用户ID的子进程数

25

_POSIX_HOST_NAME_MAX gethostname函数返回的主机名最大长度

255

_POSIX_LINK_MAX 指向一个文件的链接数

8

_POSIX_LOGIN_NAME_MAX 登录名的最大长度

9

_POSIX_MAX_CANON 终端规范输入队列的字节数

255

_POSIX_MAX_INPUT 终端输入队列的可用空间

255

_POSIX_NAME_MAX 文件名中的字节数,不包括终止字符null

14

_POSIX_NGROUPS_MAX 每个进程同时对添加组ID数

8

_POSIX_OPEN_MAX 每个进程的打开文件数

20

_POSIX_PATH_MAX 路径名中的字节数,包括终止字符null

256

_POSIX_PIPE_BUF 能原子地写到管道的字节数

512

_POSIX_RE_DUP_MAX 当使用间隔表示法\{m,n\}时,regexec和regcomp函数允许的基本正则表达式的重复出现次数

255

_POSIX_SSIZE_MAX 能存储在ssize_t对象中的值

32767

_POSIX_STREAM_MAX 一个进程能同时打开的标准I/O流数

8

_POSIX_SYMLINK_MAX 符号链接中的字节数

255

_POSIX_SYMLOOP_MAX 在解析路径名时可遍历的符号链接数

8

_POSIX_TTY_NAME_MAX 终端设备名长度,包括终止字符null

9

_POSIX_TZNAME_MAX 时区名字节数

6

上述5类共44个限制和常量中,有一些可定义在<limits.h>中,其余的则按照具体条件可定义或不定义。

表3中列出了19个不变最小值,这些值是不变的——它们并不随系统而改变。它们指定了这些特征最具约束性的值。一个符合POSIX.1的实现应当提供至少这样大的值。这就是为什么将它们称为最小值的原因,虽然它们的名字都包含了MAX。另外,为了保证可移植性,一个严格遵循POSIX的应用程序不应要求更大的值。

一个严格遵循(strictly conforming)POSIX的应用程序有别于仅遵循POSIX(merely POSIX Confirming)的应用程序。一个遵循POSIX的应用程序只使用在IEEE标准1003.1-2001中定义的接口。一个严格遵循POSIX的应用程序也是遵循POSIX的,但除此之外,它还应不依赖于POSIX未定义的行为,不使用任何已废弃的接口,以及不要求所使用的常量值大于上表中所列出的最小值。

不幸的是,这些不变最小值中的某一些在实际应用中太小了。例如,目前在大多数UNIX系统中,每个进程可同时打开的文件数远远超过20。另外,_POSIX_PATH_MAX的最小限制值为255,这也太小了,路径名可能会超过这一限制。这意味着在编译时不能使用_POSIX_OPEN_MAX和_POSIX_PATH_MAX这两个常量作为数组长度。

表3中的每一个不变最小值都有一个相关的实现值,其名字是将表中的名字删除前缀_POSIX_后构成的。不带有前导_POSIX_的名称打算作为给定实现支持的实际值(这19个实现值是上面5类中(2)-(5):不变值、运行时可增加的值、运行时不变的值以及路径名可变值)。问题是并不能确保所有这19个实现值都在<limits.h>头文件中定义。

例如,某个特定值可能不在此头文件中定义,其理由是:一个给定进程的实际值可能依赖于系统的存储总量。如果没有在头文件中定义这些值,则不能在编译时使用它们作为数组边界。所以POSIX提供了三个运行时函数以供调用,它们是:sysconf、pathconf以及fpathconf。使用这三个函数可以在运行时得到实际的实现值。但是,还有一个问题,其中某些值由POSIX.1定义为“可能不确定的”(逻辑上无限的),这就意味着该值没有实际上限。例如在Linux中,readv或writev可用的iovec结构数仅受系统存储总量的限制。所以,在Linux系统中,IOV_MAX被认为是不确定的。

三、XSI限制

XSI还定义了处理实现限制的下面几个常量:

(1)不变最小值:表4中列出的10个常量。

(2)数值限制:LONG_BIT和WORE_BIT。

(3)运行时不变值(可能不确定):ATEXIT_MAX、IOV_MAX以及PAGE_SIZE。

表4 <limits.h>中的XSI不变最小值

名字 说明 最小可接受值 典型值
NL_ARGMAX printf和scanf调用中的最大数字值 9 9
NL_LANGMAX LANG环境变量中的最大字节数 14 14
NL_MSGMAX 最大消息数 32767 32767
NL_NMAX N对1映射字符中的最大字节数 未指定 1
NL_SETMAX 最大集合数 255 255
NL_TEXTMAX 消息字符串中的最大字符数 _POSIX2_LINE_MAX 2048
NZERO 默认的进程优先级 20 20
_XOPEN_IOV_MAX readv或writev可使用的最大iovec结构数 16 16
_XOPEN_NAME_MAX 文件名中的字节数 255 255
_XOPEN_PATH_MAX 路径名中的字节数 1024 1024

四、sysconf、pathconf和fpathconf函数

我们已列出了实现必须支持的各种最小值,但是怎样才能找到一个特定系统实际支持的限制值呢?正如前面提到的,某些限制值在编译时是可用的,而另外一些则必须在运行时确定。我们也曾提及在一个给定的系统中某些限制值是不会更改的,而其他限制值则与文件和目录相关联,是可以改变的。运行时限制可通过调用下面三个函数中的一个而取得:

#include <unistd.h>
      long sysconf( int name );
      long pathconf( const char *pathname, int name );
      long fpathconf( int filedes, int name );

所有函数返回值:若成功则返回相应值;若出错则返回-1。(此处说的有点太过笼统,可参考下面的英文解释了解详情)

SYNOPSIS
       #include <unistd.h>

long sysconf(int name);

DESCRIPTION
       POSIX  allows  an application to test at compile- or run-time whether cer-
       tain options are supported, or what the value is of  certain  configurable
       constants or limits.

RETURN VALUE
       If  name  is  invalid, -1 is returned, and errno is set to EINVAL.  Other-
       wise, the value returned is the value of the system resource and errno  is
       not  changed.  In  the case of options, a positive value is returned if a
       queried option is available, and -1 if it is not.  In the case of  limits,
       -1 means that there is no definite limit.

SYNOPSIS
       #include <unistd.h>

long fpathconf(int filedes, int name);
       long pathconf(char *path, int name);

DESCRIPTION
       fpathconf()  gets  a  value for the configuration option name for the open
       file descriptor filedes.

pathconf() gets a value for configuration option  name  for  the  filename
       path.

RETURN VALUE
       The limit is returned, if one exists.  If the system does not have a limit
       for  the  requested  resource, -1 is returned, and errno is unchanged.  If
       there is an error, -1 is returned, and errno is set to reflect the  nature
       of the error.

后两个函数之间的差别是一个用路径名作为其参数,另一个则取文件描述符作为参数。

表5 sysconf的限制及name参数(用于标识系统限制,以_SC_开始的常量用作标识运行时限制的sysconf参数)

限制名 说明 name参数
ARG_MAX exec函数的参数最大长度(字节数) _SC_ARG_MAX
ATEXIT_MAX 可用atexit函数登记的最大函数个数 _SC_ATEXIT_MAX
CHILD_MAX 每个实际用户ID的最大进程数 _SC_CHILD_MAX
clock ticks/second 每秒时钟滴答数 _SC_CLK_TCK
COLL_WEIGHTS_MAX 在本地定义文件中可以赋予LC_COLLATE顺序关键字项的最大权重数 _SC_COLL_WEIGHTS_MAX
HOST_NAME_MAX gethostname函数返回的主机名最大长度 _SC_HOST_NAME_MAX
IOV_MAX readv或writev函数可以使用的iovec结构的最大数 _SC_IOV_MAX
LINE_MAX 实用程序输入行的最大长度 _SC_LINE_MAX
LOGIN_NAME_MAX 登录名的最大长度 _SC_LOGIN_NAME_MAX
NGROUPS_MAX 每个进程同时添加的最大进程组ID数 _SC_NGROUPS_MAX
OPEN_MAX 每个进程的最大打开文件数 _SC_OPEN_MAX
PAGESIZE 系统存储页长度(字节数) _SC_PAGESIZE
PAGE_SIZE 系统存储页长度(字节数) _SC_PAGE_SIZE
RE_DUP_MAX 当使用间隔表示法\{m,n\}时,regexec和regcomp函数允许的基本正则表达式的重复出现次数 _SC_RE_DUP_MAX
STREAM_MAX 在任一时刻每个进程的最大标准I/O流数,如若定义,则其值一定与FOPEN_MAX相同 _SC_STREAM_MAX
SYMLOOP_MAX 在解析路名期间,可遍历的符号链接数 _SC_SYMLOOP_MAX
TTY_NAME_MAX 终端设备名长度,包括终止字符null _SC_TTY_NAME_MAX
TZNAME_MAX 时区名的最大字节数 _SC_TZNAME_MAX

表6 pathconf和fpathconf的限制及name参数(以_PC_开始的常量用作标识运行时限制的pathconf或fpathconf参数)

限制名 说明 name参数
FILESIZEBITS 以带符号整型值表示在指定目录中允许的普通文件最大长度所需的最少位数 _PC_FILESIZEBITS
LINK_MAX 文件链接数的最大值 _PC_LINK_MAX
MAX_CANON 终端规范输入队列的最大字节数 _PC_MAX_CANON
MAX_INPUT 终端输入队列可用空间的字节数 _PC_MAX_INPUT
NAME_MAX 文件名的最大字节数(不包括终止字符null) _PC_NAME_MAX
PATH_MAX 相对路径名的最大字节数,包括终止字符null _PC_PATH_MAX
PIPE_BUF 能原子地写到管道的最大字节数 _PC_PIPE_BUF
SYMLINK_MAX 符号链接中的字节数 _PC_SYMLINK_MAX

我们需要更详细地说明这三个函数的不同返回值:

(1)如果name不是表5和表6的第3列中的一个合适的常量,则所有这三个函数都会返回-1,并将errno设置为EINVAL。

(2)有些name可以返回变量的值(返回值>=0),或者返回-1,这表示该值是不确定的,此时并不改变errno的值。

(3)_SC_CLK_TCK的返回值是每秒钟的时钟滴答数,以用于times函数的返回值。

对于pathconf的参数pathname以及fpathconf的参数filedes有一些限制。如果不满足其中任何一个限制,则结果是未定义的:

(1)_PC_MAX_CANON和_PC_MAX_INPUT所引用的文件必须是终端文件。

(2)_PC_LINK_MAX所引用的文件可以是文件或目录。如果是目录,则返回值用于目录本身(而不是用于目录内的文件名项)。

(3)_PC_FILESIZEBITS和_PC_NAME_MAX所引用的文件必须是目录,返回值用于该目录中的文件名。

(4)_PC_PATH_MAX引用的文件必须是目录。当所指定的目录是工作目录时,返回值是相对路径名的最大长度(不幸的是,这不是我们想要知道的一个绝对路径名的实际最大长度)。

(5)_PC_PIPE_BUF所引用的文件必须是管道、FIFO或目录。在管道或FIFO情况下,返回值是对所引用的管道或FIFO的限制值。对于目录,返回值是对在该目录中创建的任一FIFO的限制值。

(6)_PC_SYMLINK_MAX所引用的文件必须是目录。返回值是该目录中符号链接可能包含的字符串的最大长度。

程序清单2-1 构建C程序以打印所有得到支持的系统配置限制(竟然可以使用awk编写C程序,就这个实例来说,使用awk构建C程序比直接编写要简单高效多了)

  1. [root@localhost apue]# cat prog2-1.awk
  2. BEGIN{
  3. printf("#include \"apue.h\"\n")
  4. printf("#include <errno.h>\n")
  5. printf("#include <limits.h>\n")
  6. printf("\n")
  7. printf("static void pr_sysconf(char *, int);\n")
  8. printf("static void pr_pathconf(char *, char *, int);\n")
  9. printf("\n")
  10. printf("int\n")
  11. printf("main(int argc, char *argv[])\n")
  12. printf("{\n")
  13. printf("\tif(argc != 2)\n")
  14. printf("\t\terr_quit(\"usage: a.out <dirname>\");\n\n")
  15. FS="\t+"
  16. while(getline <"sysconf.sym" > )
  17. {
  18. printf("#ifdef %s\n", $)
  19. printf("\tprintf(\"%s defined to be %%d\\n\", %s+0);\n", $, $)
  20. printf("#else\n")
  21. printf("\tprintf(\"no symbol for %s\\n\");\n", $)
  22. printf("#endif\n")
  23. printf("#ifdef %s\n", $)
  24. printf("\tpr_sysconf(\"%s =\", %s);\n", $, $)
  25. printf("#else\n")
  26. printf("\tprintf(\"no symbol for %s\\n\");\n", $)
  27. printf("#endif\n")
  28. }
  29. close("sysconf.sym")
  30.  
  31. while(getline <"pathconf.sym" > )
  32. {
  33. printf("#ifdef %s\n", $)
  34. printf("\tprintf(\"%s defined to be %%d\\n\", %s+0);\n", $, $)
  35. printf("#else\n")
  36. printf("\tprintf(\"no symbol for %s\\n\");\n", $)
  37. printf("#endif\n")
  38. printf("#ifdef %s\n", $)
  39. printf("\tpr_pathconf(\"%s =\", argv[1], %s);\n", $, $)
  40. printf("#else\n")
  41. printf("\tprintf(\"no symbol for %s\\n\");\n", $)
  42. printf("#endif\n")
  43. }
  44. close("pathconf.sym")
  45. exit
  46. }
  47. END{
  48. printf("\texit(0);\n")
  49. printf("}\n\n")
  50. printf("static void\n")
  51. printf("pr_sysconf(char *mesg, int name)\n")
  52. printf("{\n")
  53. printf("\tlong val;\n\n")
  54. printf("\tfputs(mesg, stdout);\n")
  55. printf("\terrno = 0;\n")
  56. printf("\tif((val = sysconf(name)) < 0) {\n")
  57. printf("\t\tif(errno != 0) {\n")
  58. printf("\t\t\tif(errno == EINVAL)\n")
  59. printf("\t\t\t\tfputs(\" (not supported)\\n\", stdout);\n")
  60. printf("\t\t\telse\n")
  61. printf("\t\t\t\terr_sys(\"sysconf error\");\n")
  62. printf("\t\t} else {\n")
  63. printf("\t\t\tfputs(\"(no limit)\\n\", stdout);\n")
  64. printf("\t\t}\n")
  65. printf("\t}else {\n")
  66. printf("\t\tprintf(\" %%ld\\n\", val);\n")
  67. printf("\t}\n")
  68. printf("}\n\n")
  69. printf("static void\n")
  70. printf("pr_pathconf(char *mesg, char *path, int name)\n")
  71. printf("{\n")
  72. printf("\tlong val;\n")
  73. printf("\n")
  74. printf("\tfputs(mesg, stdout);\n")
  75. printf("\terrno = 0;\n")
  76. printf("\tif((val = pathconf(path, name)) < 0) {\n")
  77. printf("\t\tif(errno != 0){\n")
  78. printf("\t\t\tif(errno == EINVAL)\n")
  79. printf("\t\t\t\tfputs(\" (not supported)\\n\", stdout);\n")
  80. printf("\t\t\telse\n")
  81. printf("\t\t\t\terr_sys(\"pathconf error, path = %%s\", path);\n")
  82. printf("\t\t} else {\n")
  83. printf("\t\t\tfputs(\" (no limits)\\n\", stdout);\n")
  84. printf("\t\t}\n")
  85. printf("\t} else {\n")
  86. printf("\t\tprintf(\" %%ld\\n\", val);\n")
  87. printf("\t}\n")
  88. printf("}\n")
  89. }

该awk程序读取两个输入文件——pathconf.sym和sysconf.sym(可从www.apuebook.com获取),这两个文件中包含了用制表符分隔的限制名和符号列表。并非每种平台都会定义所有符号,所以围绕每个pathconf和sysconf调用,awk程序都使用了必要的#ifdef语句。

例如,awk程序将输入文件中类似于下列形式的行:

  1. NAME_MAX _PC_NAME_MAX

转换成下列C代码:

  1. #ifdef NAME_MAX
  2. printf("NAME_MAX defined to be %d\n", NAME_MAX+);
  3. #else
  4. printf("no symbol for NAME_MAX\n");
  5. #endif
  6. #ifdef _PC_NAME_MAX
  7. pr_pathconf("NAME_MAX =", argv[], _PC_NAME_MAX);
  8. #else
  9. printf("no symbol for _PC_NAME_MAX\n");
  10. #endif

要使用程序清单2-1生成C程序代码程序清单2-2,只要在命令终端运行命令:

  1. [root@localhost apue]# awk -f prog2-.awk sysconf.sym pathconf.sym >prog2-.c

即可产生如下的prog2-2.c

程序清单2-2 打印所有可能的sysconf和pathconf值

  1. [root@localhost apue]# cat prog2-.c
  2. #include "apue.h"
  3. #include <errno.h>
  4. #include <limits.h>
  5.  
  6. static void pr_sysconf(char *, int);
  7. static void pr_pathconf(char *, char *, int);
  8.  
  9. int
  10. main(int argc, char *argv[])
  11. {
  12. if(argc != )
  13. err_quit("usage: a.out <dirname>");
  14.  
  15. #ifdef ARG_MAX
  16. printf("ARG_MAX defined to be %d\n", ARG_MAX+);
  17. #else
  18. printf("no symbol for ARG_MAX\n");
  19. #endif
  20. #ifdef _SC_ARG_MAX
  21. pr_sysconf("ARG_MAX =", _SC_ARG_MAX);
  22. #else
  23. printf("no symbol for _SC_ARG_MAX\n");
  24. #endif
  25. #ifdef ATEXIT_MAX
  26. printf("ATEXIT_MAX defined to be %d\n", ATEXIT_MAX+);
  27. #else
  28. printf("no symbol for ATEXIT_MAX\n");
  29. #endif
  30. #ifdef _SC_ATEXIT_MAX
  31. pr_sysconf("ATEXIT_MAX =", _SC_ATEXIT_MAX);
  32. #else
  33. printf("no symbol for _SC_ATEXIT_MAX\n");
  34. #endif
  35. #ifdef CHARCLASS_NAME_MAX
  36. printf("CHARCLASS_NAME_MAX defined to be %d\n", CHARCLASS_NAME_MAX+);
  37. #else
  38. printf("no symbol for CHARCLASS_NAME_MAX\n");
  39. #endif
  40. #ifdef _SC_CHARCLASS_NAME_MAX
  41. pr_sysconf("CHARCLASS_NAME_MAX =", _SC_CHARCLASS_NAME_MAX);
  42. #else
  43. printf("no symbol for _SC_CHARCLASS_NAME_MAX\n");
  44. #endif
  45. #ifdef CHILD_MAX
  46. printf("CHILD_MAX defined to be %d\n", CHILD_MAX+);
  47. #else
  48. printf("no symbol for CHILD_MAX\n");
  49. #endif
  50. #ifdef _SC_CHILD_MAX
  51. pr_sysconf("CHILD_MAX =", _SC_CHILD_MAX);
  52. #else
  53. printf("no symbol for _SC_CHILD_MAX\n");
  54. #endif
  55. #ifdef CLOCKTICKSPERSECOND /*clock ticks/second*/
  56. printf("CLOCKTICKSPERSECOND /*clock ticks/second*/ defined to be %d\n", CLOCKTICKSPERSECOND /*clock ticks/second*/+);
  57. #else
  58. printf("no symbol for CLOCKTICKSPERSECOND /*clock ticks/second*/\n");
  59. #endif
  60. #ifdef _SC_CLK_TCK
  61. pr_sysconf("CLOCKTICKSPERSECOND /*clock ticks/second*/ =", _SC_CLK_TCK);
  62. #else
  63. printf("no symbol for _SC_CLK_TCK\n");
  64. #endif
  65. #ifdef COLL_WEIGHTS_MAX
  66. printf("COLL_WEIGHTS_MAX defined to be %d\n", COLL_WEIGHTS_MAX+);
  67. #else
  68. printf("no symbol for COLL_WEIGHTS_MAX\n");
  69. #endif
  70. #ifdef _SC_COLL_WEIGHTS_MAX
  71. pr_sysconf("COLL_WEIGHTS_MAX =", _SC_COLL_WEIGHTS_MAX);
  72. #else
  73. printf("no symbol for _SC_COLL_WEIGHTS_MAX\n");
  74. #endif
  75. #ifdef HOST_NAME_MAX
  76. printf("HOST_NAME_MAX defined to be %d\n", HOST_NAME_MAX+);
  77. #else
  78. printf("no symbol for HOST_NAME_MAX\n");
  79. #endif
  80. #ifdef _SC_HOST_NAME_MAX
  81. pr_sysconf("HOST_NAME_MAX =", _SC_HOST_NAME_MAX);
  82. #else
  83. printf("no symbol for _SC_HOST_NAME_MAX\n");
  84. #endif
  85. #ifdef IOV_MAX
  86. printf("IOV_MAX defined to be %d\n", IOV_MAX+);
  87. #else
  88. printf("no symbol for IOV_MAX\n");
  89. #endif
  90. #ifdef _SC_IOV_MAX
  91. pr_sysconf("IOV_MAX =", _SC_IOV_MAX);
  92. #else
  93. printf("no symbol for _SC_IOV_MAX\n");
  94. #endif
  95. #ifdef LINE_MAX
  96. printf("LINE_MAX defined to be %d\n", LINE_MAX+);
  97. #else
  98. printf("no symbol for LINE_MAX\n");
  99. #endif
  100. #ifdef _SC_LINE_MAX
  101. pr_sysconf("LINE_MAX =", _SC_LINE_MAX);
  102. #else
  103. printf("no symbol for _SC_LINE_MAX\n");
  104. #endif
  105. #ifdef LOGIN_NAME_MAX
  106. printf("LOGIN_NAME_MAX defined to be %d\n", LOGIN_NAME_MAX+);
  107. #else
  108. printf("no symbol for LOGIN_NAME_MAX\n");
  109. #endif
  110. #ifdef _SC_LOGIN_NAME_MAX
  111. pr_sysconf("LOGIN_NAME_MAX =", _SC_LOGIN_NAME_MAX);
  112. #else
  113. printf("no symbol for _SC_LOGIN_NAME_MAX\n");
  114. #endif
  115. #ifdef NGROUPS_MAX
  116. printf("NGROUPS_MAX defined to be %d\n", NGROUPS_MAX+);
  117. #else
  118. printf("no symbol for NGROUPS_MAX\n");
  119. #endif
  120. #ifdef _SC_NGROUPS_MAX
  121. pr_sysconf("NGROUPS_MAX =", _SC_NGROUPS_MAX);
  122. #else
  123. printf("no symbol for _SC_NGROUPS_MAX\n");
  124. #endif
  125. #ifdef OPEN_MAX
  126. printf("OPEN_MAX defined to be %d\n", OPEN_MAX+);
  127. #else
  128. printf("no symbol for OPEN_MAX\n");
  129. #endif
  130. #ifdef _SC_OPEN_MAX
  131. pr_sysconf("OPEN_MAX =", _SC_OPEN_MAX);
  132. #else
  133. printf("no symbol for _SC_OPEN_MAX\n");
  134. #endif
  135. #ifdef PAGESIZE
  136. printf("PAGESIZE defined to be %d\n", PAGESIZE+);
  137. #else
  138. printf("no symbol for PAGESIZE\n");
  139. #endif
  140. #ifdef _SC_PAGESIZE
  141. pr_sysconf("PAGESIZE =", _SC_PAGESIZE);
  142. #else
  143. printf("no symbol for _SC_PAGESIZE\n");
  144. #endif
  145. #ifdef PAGE_SIZE
  146. printf("PAGE_SIZE defined to be %d\n", PAGE_SIZE+);
  147. #else
  148. printf("no symbol for PAGE_SIZE\n");
  149. #endif
  150. #ifdef _SC_PAGE_SIZE
  151. pr_sysconf("PAGE_SIZE =", _SC_PAGE_SIZE);
  152. #else
  153. printf("no symbol for _SC_PAGE_SIZE\n");
  154. #endif
  155. #ifdef RE_DUP_MAX
  156. printf("RE_DUP_MAX defined to be %d\n", RE_DUP_MAX+);
  157. #else
  158. printf("no symbol for RE_DUP_MAX\n");
  159. #endif
  160. #ifdef _SC_RE_DUP_MAX
  161. pr_sysconf("RE_DUP_MAX =", _SC_RE_DUP_MAX);
  162. #else
  163. printf("no symbol for _SC_RE_DUP_MAX\n");
  164. #endif
  165. #ifdef STREAM_MAX
  166. printf("STREAM_MAX defined to be %d\n", STREAM_MAX+);
  167. #else
  168. printf("no symbol for STREAM_MAX\n");
  169. #endif
  170. #ifdef _SC_STREAM_MAX
  171. pr_sysconf("STREAM_MAX =", _SC_STREAM_MAX);
  172. #else
  173. printf("no symbol for _SC_STREAM_MAX\n");
  174. #endif
  175. #ifdef SYMLOOP_MAX
  176. printf("SYMLOOP_MAX defined to be %d\n", SYMLOOP_MAX+);
  177. #else
  178. printf("no symbol for SYMLOOP_MAX\n");
  179. #endif
  180. #ifdef _SC_SYMLOOP_MAX
  181. pr_sysconf("SYMLOOP_MAX =", _SC_SYMLOOP_MAX);
  182. #else
  183. printf("no symbol for _SC_SYMLOOP_MAX\n");
  184. #endif
  185. #ifdef TTY_NAME_MAX
  186. printf("TTY_NAME_MAX defined to be %d\n", TTY_NAME_MAX+);
  187. #else
  188. printf("no symbol for TTY_NAME_MAX\n");
  189. #endif
  190. #ifdef _SC_TTY_NAME_MAX
  191. pr_sysconf("TTY_NAME_MAX =", _SC_TTY_NAME_MAX);
  192. #else
  193. printf("no symbol for _SC_TTY_NAME_MAX\n");
  194. #endif
  195. #ifdef TZNAME_MAX
  196. printf("TZNAME_MAX defined to be %d\n", TZNAME_MAX+);
  197. #else
  198. printf("no symbol for TZNAME_MAX\n");
  199. #endif
  200. #ifdef _SC_TZNAME_MAX
  201. pr_sysconf("TZNAME_MAX =", _SC_TZNAME_MAX);
  202. #else
  203. printf("no symbol for _SC_TZNAME_MAX\n");
  204. #endif
  205. #ifdef MAX_CANON
  206. printf("MAX_CANON defined to be %d\n", MAX_CANON+);
  207. #else
  208. printf("no symbol for MAX_CANON\n");
  209. #endif
  210. #ifdef _PC_MAX_CANON
  211. pr_pathconf("MAX_CANON =", argv[], _PC_MAX_CANON);
  212. #else
  213. printf("no symbol for _PC_MAX_CANON\n");
  214. #endif
  215. #ifdef MAX_INPUT
  216. printf("MAX_INPUT defined to be %d\n", MAX_INPUT+);
  217. #else
  218. printf("no symbol for MAX_INPUT\n");
  219. #endif
  220. #ifdef _PC_MAX_INPUT
  221. pr_pathconf("MAX_INPUT =", argv[], _PC_MAX_INPUT);
  222. #else
  223. printf("no symbol for _PC_MAX_INPUT\n");
  224. #endif
  225. #ifdef FILESIZEBITS
  226. printf("FILESIZEBITS defined to be %d\n", FILESIZEBITS+);
  227. #else
  228. printf("no symbol for FILESIZEBITS\n");
  229. #endif
  230. #ifdef _PC_FILESIZEBITS
  231. pr_pathconf("FILESIZEBITS =", argv[], _PC_FILESIZEBITS);
  232. #else
  233. printf("no symbol for _PC_FILESIZEBITS\n");
  234. #endif
  235. #ifdef LINK_MAX
  236. printf("LINK_MAX defined to be %d\n", LINK_MAX+);
  237. #else
  238. printf("no symbol for LINK_MAX\n");
  239. #endif
  240. #ifdef _PC_LINK_MAX
  241. pr_pathconf("LINK_MAX =", argv[], _PC_LINK_MAX);
  242. #else
  243. printf("no symbol for _PC_LINK_MAX\n");
  244. #endif
  245. #ifdef NAME_MAX
  246. printf("NAME_MAX defined to be %d\n", NAME_MAX+);
  247. #else
  248. printf("no symbol for NAME_MAX\n");
  249. #endif
  250. #ifdef _PC_NAME_MAX
  251. pr_pathconf("NAME_MAX =", argv[], _PC_NAME_MAX);
  252. #else
  253. printf("no symbol for _PC_NAME_MAX\n");
  254. #endif
  255. #ifdef PATH_MAX
  256. printf("PATH_MAX defined to be %d\n", PATH_MAX+);
  257. #else
  258. printf("no symbol for PATH_MAX\n");
  259. #endif
  260. #ifdef _PC_PATH_MAX
  261. pr_pathconf("PATH_MAX =", argv[], _PC_PATH_MAX);
  262. #else
  263. printf("no symbol for _PC_PATH_MAX\n");
  264. #endif
  265. #ifdef PIPE_BUF
  266. printf("PIPE_BUF defined to be %d\n", PIPE_BUF+);
  267. #else
  268. printf("no symbol for PIPE_BUF\n");
  269. #endif
  270. #ifdef _PC_PIPE_BUF
  271. pr_pathconf("PIPE_BUF =", argv[], _PC_PIPE_BUF);
  272. #else
  273. printf("no symbol for _PC_PIPE_BUF\n");
  274. #endif
  275. #ifdef SYMLINK_MAX
  276. printf("SYMLINK_MAX defined to be %d\n", SYMLINK_MAX+);
  277. #else
  278. printf("no symbol for SYMLINK_MAX\n");
  279. #endif
  280. #ifdef _PC_SYMLINK_MAX
  281. pr_pathconf("SYMLINK_MAX =", argv[], _PC_SYMLINK_MAX);
  282. #else
  283. printf("no symbol for _PC_SYMLINK_MAX\n");
  284. #endif
  285. exit();
  286. }
  287.  
  288. static void
  289. pr_sysconf(char *mesg, int name)
  290. {
  291. long val;
  292.  
  293. fputs(mesg, stdout);
  294. errno = ;
  295. if((val = sysconf(name)) < ) {
  296. if(errno != ) {
  297. if(errno == EINVAL)
  298. fputs(" (not supported)\n", stdout);
  299. else
  300. err_sys("sysconf error");
  301. } else {
  302. fputs("(no limit)\n", stdout);
  303. }
  304. }else {
  305. printf(" %ld\n", val);
  306. }
  307. }
  308.  
  309. static void
  310. pr_pathconf(char *mesg, char *path, int name)
  311. {
  312. long val;
  313.  
  314. fputs(mesg, stdout);
  315. errno = ;
  316. if((val = pathconf(path, name)) < ) {
  317. if(errno != ){
  318. if(errno == EINVAL)
  319. fputs(" (not supported)\n", stdout);
  320. else
  321. err_sys("pathconf error, path = %s", path);
  322. } else {
  323. fputs(" (no limits)\n", stdout);
  324. }
  325. } else {
  326. printf(" %ld\n", val);
  327. }
  328. }

五、不确定的运行时限制

前面已经提及某些限制值可能是不确定的。我们遇到的问题是,如果这些限制值没有在头文件<limits.h>中定义,那么在编译时也就不能使用它们。但是,如果它们的值是不确定的,那么在运行时它们可能也是未定义的!让我们来观察两种特殊的情况:为一个路径名分配存储区,以及确定文件描述符的数目。

1、路径名

很多程序需要为路径名分配存储区。一般来说,在编译时就为其分配了存储区,而且不同的程序使用各种不同的幻数(其中很少是正确的)作为数组长度。例如,256、512、1024或标准I/O常量BUFSIZ。4.3BSD头文件<sys/param.h>中的常量MAXPATHLEN是正确的,但是很多4.3BSD应用程序并未使用它。

POSIX.1试图使用PATH_MAX值来帮助我们,但是如果此值是不确定的,那么仍是毫无帮助的。

如若在<limits.h>中定义了常量PATH_MAX,那么就没有任何问题;如果没有定义,则需调用pathconf。因为pathconf的返回值是基于工作目录的相对路径名的最大长度,而工作目录是其第一个参数,所以,指定根目录为第一个参数,并将得到的返回值加1作为结果值。如果pathconf指明PATH_MAX是不确定的,那么我们就只能猜测某个值。

对于PATH_MAX是否在路径名末尾包括一个null字符这一点,SUS v3之前的标准表述得不清楚。出于安全方面的考虑,如果操作系统实现遵循先前的标准版本,则需要在为路径名分配的存储数量上加1。

处理不确定结果这种情况的正确方法与如何使用所分配的存储空间有关。例如,如果我们为getcwd调用分配空间(返回当前工作目录的绝对路径名),并且分配的空间太小,则返回一个出错,并将errno设置为ERANGE。然后可调用realloc来增加分配的空间并重试。不断重复此操作,直到getcwd调用成功执行。

程序清单2-3 为路径名动态地分配空间

  1. [root@localhost apue]# cat prog2-.c
  2. #include "apue.h"
  3. #include <errno.h>
  4. #include <limits.h>
  5.  
  6. #ifdef PATH_MAX
  7. static int pathmax = PATH_MAX;
  8. #else
  9. static int pathmax = ;
  10. #endif
  11.  
  12. #define SUSV3 200112L
  13.  
  14. static long posix_version = ;
  15.  
  16. /* If PATH_MAX is indeterminate, no guarantee this is adequate */
  17. #define PATH_MAX_GUESS 1024
  18.  
  19. char *
  20. path_alloc(int *sizep) /* also return allocated size, if nonull */
  21. {
  22. char *ptr;
  23. int size;
  24.  
  25. if(posix_version == )
  26. posix_version = sysconf(_SC_VERSION);
  27.  
  28. if(pathmax == ) { /* first time trough */
  29. errno = ;
  30. if((pathmax = pathconf("/", _PC_PATH_MAX)) < ) {
  31. if(errno == )
  32. pathmax = PATH_MAX_GUESS; /* it's indeterminate */
  33. else
  34. err_sys("pathconf error for _PC_PATH_MAX");
  35. } else {
  36. pathmax++; /* add one since it's relative to root */
  37. }
  38. }
  39. if(posix_version < SUSV3)
  40. size = pathmax + ;
  41. else
  42. size = pathmax;
  43.  
  44. if((ptr = malloc(size)) == NULL)
  45. err_sys("malloc error for pathname");
  46.  
  47. if(sizep != NULL)
  48. *sizep = size;
  49. return(ptr);
  50. }

2、最大打开文件数

守护进程(daemon process,是指在后台运行且不与终端相连接的一种进程,也常被称为精灵进程或后台进程)中一个常见的代码序列是关闭所有打开的文件。某些程序中有下列形式的代码序列:

  1. #include <sys/param.h>
  2.  
  3. for( i=; i<NOFILE; i++ )
  4. close( i );

这段程序假定在<sys/param.h>头文件中定义了常量NOFILE。另外一些程序则使用某些<stdio.h>版本提供作为上限的常量_NFILE。某些程序则将其上限值硬编码为20.

我们希望用POSIX.1的OPEN_MAX来确定此值以提高可移植性,但是,如果此值是不确定的,则仍然有问题。如果我们编写了下列代码:

  1. #include <unistd.h>
  2.  
  3. for( i=; i<sysconf( _SC_OPEN_MAX ); i++ )
  4. close( i );

而且如果OPEN_MAX是不确定的,那么for循环根本不会执行因为sysconf将返回-1。在这种情况下,最好的选择就是关闭所有描述符直至某个限制值(例如256)。如同上面的路径名实例一样,这样并不能保证在所有情况下都能正常工作,但这却是我们所能选择的最好方法。程序清单2-4中使用了这种技术:

程序清单2-4 确定文件描述符数

  1. [root@localhost apue]# cat prog2-.c
  2. #include "apue.h"
  3. #include <errno.h>
  4. #include <limits.h>
  5.  
  6. #ifdef OPEN_MAX
  7. static long openmax = OPEN_MAX;
  8. #else
  9. static long openmax = ;
  10. #endif
  11.  
  12. /*
  13. * If OPEN_MAX is indeterminate, we're not
  14. * guaranteed than this is adequate.
  15. */
  16. #define OPEN_MAX_GUESS 256
  17.  
  18. long
  19. open_max(void)
  20. {
  21. if(openmax == ) { /* first time through */
  22. errno = ;
  23. if((openmax = sysconf(_SC_OPEN_MAX)) < ) {
  24. if(errno == )
  25. openmax = OPEN_MAX_GUESS; /* it's indeterminate */
  26. else
  27. err_sys("sysconf error for _SC_OPEN_MAX");
  28. }
  29. }
  30. return(openmax);
  31. }

我们可以耐心地调用close,直至得到一个出错返回,但是从close(EBADF)出错返回并不区分无效描述符和没有打开的描述符。如果使用此技术,而且描述符9未打开,描述符10却打开了,那么将停止在9上,而不会关闭10.

某些实现将返回LONG_MAX作为限制值,但这与不限制其值在效果上是相同的。Linux对ATEXIT_MAX所取的限制值就属于此种情况。这将使程序的运行行为变得非常糟糕(浪费大量时间),因此它并不是一个好方法。

本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

UNIX标准化及实现之限制的更多相关文章

  1. UNIX标准化及实现之UNIX标准化、UNIX系统实现、标准和实现的关系以及ISO C标准头文件

    一.UNIX标准化 1.ISO C (International Organization for Standardization) 2.IEEE POSIX (Institue of Electri ...

  2. 《UNIX环境高级编程》笔记--UNIX标准化及实现

    1.UNIX标准化 1.1.ISO C 1989 年后期,C程序设计语言的ANSI(American National Standards Institute) 标准X3. 15 9-1989得到批准 ...

  3. 第二章:UNIX标准化及实现

    本章节介绍个UNIX编程环境的标准化的进展,对ISO C,POSIX和Single UNIX Specification三个主要标准进行了说明 本章后面部分介绍了限制的具体实例. 我学习本章的心得是: ...

  4. UNIX标准化及实现之POSIX标准必需头文件

    POSIX标准定义的必需头文件 头文件 说明 <dirent.h> 目录项 <fcntl.h> 文件控制 <fnmatch.h> 文件名匹配类型 <glob. ...

  5. UNIX标准化及实现之标准之间的冲突

    就整体而言,这些不同的标准之间配合得相当好.但是我们也很关注它们之间的差别,特别是ISO C标准和POSIX.1之间的差别. ISO C定义了函数clock,它返回进程使用的CPU时间,返回值类型是c ...

  6. UNIX标准化及实现之基本系统数据类型

    历史上,某些UNIX系统变量已与某些C数据类型联系在一起.例如,历史上主.次设备号一直存放在一个16位的短整型中,8位表示主设备号,另外8位表示次设备号.但是,很多较大的系统需要用多于256个值来表示 ...

  7. UNIX标准化及实现之功能测试宏

    在头文件中定义了很多POSIX.1和XSI的符号.但是除了POSIX.1和XSI的定义之外,大多数实现在这些头文件中也加上了它们自己的定义.如果在编译一个程序时,希望它只使用POSIX定义而不使用任何 ...

  8. UNIX标准化及实现之选项

    POSIX.1的2001版,包括了ISO C标准所指定的各个函数.其接口分成了两类:必需接口和可选接口.可选接口按功能又进一步分成50个区.表1中按它们各自的选项代码总结了没有被弃用的编程接口.选项代 ...

  9. UNIX标准化及实现之POSIX标准可选头文件

    POSIX标准定义的可选头文件 头文件 说明 <aio.h> 异步I/O <mqueue.h> 消息队列 <pthread.h> 线程 <sched.h> ...

随机推荐

  1. 使用Visual Studio 2013对windows应用商店应用进行编码的UI测试

    之前进行了一次实验,实验内容是对windows应用商店应用进行编码的UI测试,下面对实验步骤进行详细说明: 1.为 Windows 应用商店应用创建新编码的 UI 测试项目,选择Visual C##→ ...

  2. 关于Windows 7的64位系统不兼容某些控件的问题

    我的问题是vsflex7.ocx 不能在64位系统下运行,导致软件的一个涉及到这个控件的功能出错.如下: 解决的办法基本思路是把这个控件注册一下.然后就可以了.就是这个控件: 目录中没有自己下载个. ...

  3. 使用MATLAB生成模糊控制的离线查询表

    1.打开模糊控制工具箱,编辑输入输出变量的隶属度函数和模糊控制规则,如下图所示,导出为fuzzy_control.fis文件. 2.打开Simulink模块,建立下图所示的系统框图,两输入,一输出,处 ...

  4. leetcode@ [336] Palindrome Pairs (HashMap)

    https://leetcode.com/problems/palindrome-pairs/ Given a list of unique words. Find all pairs of dist ...

  5. iOS图形处理和性能

    转自陶丰平的博客   原文的题目是Designing for iOS: Graphics & Performance,晚上花了两个不到小时大致翻译了下. ---Begin--- 在之前的文章里 ...

  6. Gym 100507D Zhenya moves from the dormitory (模拟)

    Zhenya moves from the dormitory 题目链接: http://acm.hust.edu.cn/vjudge/contest/126546#problem/D Descrip ...

  7. TTL电平、CMOS电平、RS232电平的区别

    工作中遇到一个关于电平选择的问题,居然给忘记RS232电平的定义了,当时无法反应上来,回来之后查找资料才了解两者之间的区别,视乎两年多的时间,之前非常熟悉的一些常识也开始淡忘,这个可不是一个好的现象. ...

  8. 51单片机或PLC驱动3.5寸至52寸的数字TFTLCD屏、VGA接口显示器、电视机

    http://www.21easyic.com/yx/VGA%E6%8E%A7%E5%88%B6%E6%9D%BF.htm

  9. HDU 3577 Fast Arrangement (线段树区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3577 题意不好理解,给你数字k表示这里车最多同时坐k个人,然后有q个询问,每个询问是每个人的上车和下车 ...

  10. 340. Longest Substring with At Most K Distinct Characters

    最后更新 二刷 08-Jan-2017 和76.159很像.. 2 pointers.. 通过判断是否每一次是有效读取来增减accumulator,从而判断当前是否符合规定,再来更新maxLength ...