5、一些限制
实现定义了许多的魔术数和常量。这些值要么被硬性编码到应用程序中,要么通过特定的技术来确定。由于我们前面所叙述的各种标准化努力工作,有越来越多的可移植方法为我们提供了确定这些魔术数以及实现定义的限制(常量),有助于增加我们软件的可移植特性。
有两种类型的限制:
- 编译期间的限制(例如,最大的短整型值是多少?)
- 运行期间的限制(例如,一个文件名称中包含多少个字符?)
编译期间的限制可以在头文件中定义,由应用程序在编译期间包含那个头文件。但是运行期间的限制需要进程调用一个函数来获得限制的值。
另外,有一些限制在一个给定的实现中可能是固定的,因此可以在一个头文件中静态地定义,而在另一个实现上则可能是变动的,需要调用一个运行时函数 。例如文件名的最大字符数。系统V由于历史原因只允许文件名有14个字符,而伯克利的系统则将此增加为255。 SVR4
允许我们对每一个创建的文件系统指明是系统 V文件系统还是 BSD
文件系统,而每个系统有不同的限制。这就是运行期间限制的一个实例,即文件名的最大长度依赖于文件所处的文件系统。例如,根文件系统中的文件名长度限制可能是 14个字符,而在某个其他文件系统中文件名长度限制可能是255个字符。
为了解决这些问题,提供了三种限制:
- 编辑期间限制(头文件) 。
- 不与文件或目录相关联的运行期间限制(
sysconf
函数)。 - 与文件或目录相关联的运行期间限制(
pathconf
和fpathconf
函数集)。
更让人头痛的是,如果一个特定的运行时间限制在一个给定的系统上是固定的,那么可将其静态地定义在一个头文件中,但是,如果没有将其定义在头文件中,则应用程序就必须调用三个 conf
函数中的一个(我们很快就会对它们进行说明),以确定其运行时间值。
(下面大致对各种限制进行介绍,具体请参见参考资料)
(1) ISO C
限制
所有由 ANSI C
定义的限制都是编译时间限制。如下:
<limits.h>
中的整数值大小
+-----------------------------------------------------------------------------------------------------------+
| Name | Description | Minimum acceptable value | Typical value |
|------------+------------------------------------+----------------------------+----------------------------|
| CHAR_BIT | bits in a char | 8 | 8 |
|------------+------------------------------------+----------------------------+----------------------------|
| CHAR_MAX | max value of char | (see later) | 127 |
|------------+------------------------------------+----------------------------+----------------------------|
| CHAR_MIN | min value of char | (see later) | 128 |
|------------+------------------------------------+----------------------------+----------------------------|
| SCHAR_MAX | max value of signed char | 127 | 127 |
|------------+------------------------------------+----------------------------+----------------------------|
| SCHAR_MIN | min value of signed char | 127 | 128 |
|------------+------------------------------------+----------------------------+----------------------------|
| UCHAR_MAX | max value of unsigned char | 255 | 255 |
|------------+------------------------------------+----------------------------+----------------------------|
| INT_MAX | max value of int | 32,767 | 2,147,483,647 |
|------------+------------------------------------+----------------------------+----------------------------|
| INT_MIN | min value of int | 32,767 | 2,147,483,648 |
|------------+------------------------------------+----------------------------+----------------------------|
| UINT_MAX | max value of unsigned int | 65,535 | 4,294,967,295 |
|------------+------------------------------------+----------------------------+----------------------------|
| SHRT_MIN | min value of short | 32,767 | 32,768 |
|------------+------------------------------------+----------------------------+----------------------------|
| SHRT_MAX | max value of short | 32,767 | 32,767 |
|------------+------------------------------------+----------------------------+----------------------------|
| USHRT_MAX | max value of unsigned short | 65,535 | 65,535 |
|------------+------------------------------------+----------------------------+----------------------------|
| LONG_MAX | max value of long | 2,147,483,647 | 2,147,483,647 |
|------------+------------------------------------+----------------------------+----------------------------|
| LONG_MIN | min value of long | 2,147,483,647 | 2,147,483,648 |
|------------+------------------------------------+----------------------------+----------------------------|
| ULONG_MAX | max value of unsigned long | 4,294,967,295 | 4,294,967,295 |
|------------+------------------------------------+----------------------------+----------------------------|
| LLONG_MAX | max value of long long | 9,223,372,036,854,775,807 | 9,223,372,036,854,775,807 |
|------------+------------------------------------+----------------------------+----------------------------|
| LLONG_MIN | min value of long long | 9,223,372,036,854,775,807 | 9,223,372,036,854,775,808 |
|------------+------------------------------------+----------------------------+----------------------------|
| ULLONG_MAX | max value of unsigned long long | 18,446,744,073,709,551,615 | 18,446,744,073,709,551,615 |
|------------+------------------------------------+----------------------------+----------------------------|
| MB_LEN_MAX | max number of bytes in a multibyte | 1 | 16 |
| | character constant | | |
+-----------------------------------------------------------------------------------------------------------+
ANSI C
在 <stdio.h>
中也定义了常数 TMP_MAX
,这是由 tmpnam
函数产生的唯一文件名的大数。关于此常数我们将在第5章13节中进行更多说明。在头文件 <float.h>
中,对浮点数据类型也有类似的一组定义。下面我们给出的是我们本书中讨论的四个平台中的 FOPEN_MAX
和 TMP_MAX
。
不同平台的 ISO
限制
+----------------------------------------------------------------------+
| Limit | FreeBSD 5.2.1 | Linux 2.4.22 | Mac OS X 10.3 | Solaris 9 |
|-----------+---------------+--------------+---------------+-----------|
| FOPEN_MAX | 20 | 16 | 20 | 20 |
|-----------+---------------+--------------+---------------+-----------|
| TMP_MAX | 308,915,776 | 238,328 | 308,915,776 | 17,576 |
+----------------------------------------------------------------------+
(2) POSIX
限制
POSIX.1
定义了很多涉及操作系统实现限制的常数,其关系错综复杂。下表是 <linuxs.h>
中不变的最小值。
POSIX.1
中 <limits.h>
中的固定最小值
+-----------------------------------------------------------------------------------------------------------+
| Name | Description: minimum acceptable value for | Value |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_ARG_MAX | length of arguments to exec functions | 4,096 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_CHILD_MAX | number of child processes per real user ID | 25 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_HOST_NAME_MAX | maximum length of a host name as returned by gethostname | 255 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_LINK_MAX | number of links to a file | 8 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_LOGIN_NAME_MAX | maximum length of a login name | 9 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_MAX_CANON | number of bytes on a terminal's canonical input queue | 255 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_MAX_INPUT | space available on a terminal's input queue | 255 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_NAME_MAX | number of bytes in a filename, not including the terminating null | 14 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_NGROUPS_MAX | number of simultaneous supplementary group IDs per process | 8 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_OPEN_MAX | number of open files per process | 20 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_PATH_MAX | number of bytes in a pathname, including the terminating null | 256 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_PIPE_BUF | number of bytes that can be written atomically to a pipe | 512 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_RE_DUP_MAX | number of repeated occurrences of a basic regular expression permitted | 255 |
| | by the regexec and regcomp functions when using the interval notation \ | |
| | {m,n\} | |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_SSIZE_MAX | value that can be stored in ssize_t object | 32,767 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_STREAM_MAX | number of standard I/O streams a process can have open at once | 8 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_SYMLINK_MAX | number of bytes in a symbolic link | 255 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_SYMLOOP_MAX | number of symbolic links that can be traversed during pathname | 8 |
| | resolution | |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_TTY_NAME_MAX | length of a terminal device name, including the terminating null | 9 |
|-----------------------+--------------------------------------------------------------------------+--------|
| _POSIX_TZNAME_MAX | number of bytes for the name of a time zone | 6 |
+-----------------------------------------------------------------------------------------------------------+
这些值是不变的——它们并不随系统而改变。它们指定一个符合 POSIX.1
的实现应当提供至少这样大的值,所以它们被称为最小值的名字里面却包含 MAX
。另外,一个可移植的应用程序不应要求更大的值。我们将在本书的适当部分说明每一个常数的含意。
这些不变最小值中的某一些在实际应用中太小了,所以不变最小值的每一个都有一个相关的实现值,其名字是将上表中的名字删除前缀 _POSIX_
后构成的。这些个实现值并不能确保在 <limit.h>
头文件中定义,如果没有在头文件中定义它们,则不能在编译时使用它们作为数组边界。所以, POSIX.1
提供三个运行时间函数以供调用: sysconf
, pathconf
以及 fpathconf
,用它们可以在运行时间得到实际的实现值。还有一个问题,某些值是由 POSIX.1
定义为“可能不确定的”(逻辑上无限的),这就意味着该值没有实际上限。例如, SVR4
的每个进程打开文件数。
(3) XSI
限制
XSI
也定义了实现相关限制的常量.
XSI
中 <limits.h>
中定义的固定最小值
+-----------------------------------------------------------------------------------------------------------+
| Name | Description | Minimum acceptable | Typical |
| | | value | value |
|-----------------+-------------------------------------------------------+--------------------+------------|
| NL_ARGMAX | maximum value of digit in calls to printf and scanf | 9 | 9 |
|-----------------+-------------------------------------------------------+--------------------+------------|
| NL_LANGMAX | maximum number of bytes in LANG environment variable | 14 | 14 |
|-----------------+-------------------------------------------------------+--------------------+------------|
| NL_MSGMAX | maximum message number | 32,767 | 32,767 |
|-----------------+-------------------------------------------------------+--------------------+------------|
| NL_NMAX | maximum number of bytes in N-to-1 mapping characters | (none specified) | 1 |
|-----------------+-------------------------------------------------------+--------------------+------------|
| NL_SETMAX | maximum set number | 255 | 255 |
|-----------------+-------------------------------------------------------+--------------------+------------|
| NL_TEXTMAX | maximum number of bytes in a message string | _POSIX2_LINE_MAX | 2,048 |
|-----------------+-------------------------------------------------------+--------------------+------------|
| NZERO | default process priority | 20 | 20 |
|-----------------+-------------------------------------------------------+--------------------+------------|
| _XOPEN_IOV_MAX | maximum number of iovec structures that can be used | 16 | 16 |
| | with readv or writev | | |
|-----------------+-------------------------------------------------------+--------------------+------------|
| _XOPEN_NAME_MAX | number of bytes in a filename | 255 | 255 |
|-----------------+-------------------------------------------------------+--------------------+------------|
| _XOPEN_PATH_MAX | number of bytes in a pathname | 1,024 | 1,024 |
+-----------------------------------------------------------------------------------------------------------+
(4) sysconf
, pathconf
, and fpathconf
函数
我们给出了各种实现必须支持的最小限制,但是我们如何能够获得一个特定系统实际支持的值?我们前面说过,有些限制是编译期间可以确定的;有些必须在运行时间确定。我们也提到了有些限制在给定的系统中不会改变,另外一些由于它们和文件与目录相关,所以也可能会改变。运行期间的限制可以通过以下三个函数来获得:
#include <unistd.h>
long sysconf(int name);
long pathconf(const char *pathname, int name);
long fpathconf(int filedes, int name);
返回:如果成功,那么三个函数返回相应的值,如果错误返回1。
sysconf
的限制和名称参数
+-----------------------------------------------------------------------------------------------------------+
| Name of limit | Description | name argument |
|------------------+-----------------------------------------------------------------+----------------------|
| ARG_MAX | maximum length, in bytes, of arguments to the exec functions | _SC_ARG_MAX |
|------------------+-----------------------------------------------------------------+----------------------|
| ATEXIT_MAX | maximum number of functions that can be registered with the | _SC_ATEXIT_MAX |
| | atexit function | |
|------------------+-----------------------------------------------------------------+----------------------|
| CHILD_MAX | maximum number of processes per real user ID | _SC_CHILD_MAX |
|------------------+-----------------------------------------------------------------+----------------------|
| clock ticks/ | number of clock ticks per second | _SC_CLK_TCK |
| second | | |
|------------------+-----------------------------------------------------------------+----------------------|
| COLL_WEIGHTS_MAX | maximum number of weights that can be assigned to an entry of | _SC_COLL_WEIGHTS_MAX |
| | the LC_COLLATE order keyword in the locale definition file | |
|------------------+-----------------------------------------------------------------+----------------------|
| HOST_NAME_MAX | maximum length of a host name as returned by gethostname | _SC_HOST_NAME_MAX |
|------------------+-----------------------------------------------------------------+----------------------|
| IOV_MAX | maximum number of iovec structures that can be used with readv | _SC_IOV_MAX |
| | or writev | |
|------------------+-----------------------------------------------------------------+----------------------|
| LINE_MAX | maximum length of a utility's input line | _SC_LINE_MAX |
|------------------+-----------------------------------------------------------------+----------------------|
| LOGIN_NAME_MAX | maximum length of a login name | _SC_LOGIN_NAME_MAX |
|------------------+-----------------------------------------------------------------+----------------------|
| NGROUPS_MAX | maximum number of simultaneous supplementary process group IDs | _SC_NGROUPS_MAX |
| | per process | |
|------------------+-----------------------------------------------------------------+----------------------|
| OPEN_MAX | maximum number of open files per process | _SC_OPEN_MAX |
|------------------+-----------------------------------------------------------------+----------------------|
| PAGESIZE | system memory page size, in bytes | _SC_PAGESIZE |
|------------------+-----------------------------------------------------------------+----------------------|
| PAGE_SIZE | system memory page size, in bytes | _SC_PAGE_SIZE |
|------------------+-----------------------------------------------------------------+----------------------|
| RE_DUP_MAX | number of repeated occurrences of a basic regular expression | _SC_RE_DUP_MAX |
| | permitted by the regexec and regcomp functions when using the | |
| | interval notation \{m,n\} | |
|------------------+-----------------------------------------------------------------+----------------------|
| STREAM_MAX | maximum number of standard I/O streams per process at any given | _SC_STREAM_MAX |
| | time; if defined, it must have the same value as FOPEN_MAX | |
|------------------+-----------------------------------------------------------------+----------------------|
| SYMLOOP_MAX | number of symbolic links that can be traversed during pathname | _SC_SYMLOOP_MAX |
| | resolution | |
|------------------+-----------------------------------------------------------------+----------------------|
| TTY_NAME_MAX | length of a terminal device name, including the terminating | _SC_TTY_NAME_MAX |
| | null | |
|------------------+-----------------------------------------------------------------+----------------------|
| TZNAME_MAX | maximum number of bytes for the name of a time zone | _SC_TZNAME_MAX |
+-----------------------------------------------------------------------------------------------------------+
pathconf
和 fpathconf
的限制和名称参数
+-----------------------------------------------------------------------------------------------------------+
| Name of | | |
| limit | Description | name argument |
|--------------+-------------------------------------------------------------------------+------------------|
| FILESIZEBITS | minimum number of bits needed to represent, as a signed integer value, | _PC_FILESIZEBITS |
| | the maximum size of a regular file allowed in the specified directory | |
|--------------+-------------------------------------------------------------------------+------------------|
| LINK_MAX | maximum value of a file's link count | _PC_LINK_MAX |
|--------------+-------------------------------------------------------------------------+------------------|
| MAX_CANON | maximum number of bytes on a terminal's canonical input queue | _PC_MAX_CANON |
|--------------+-------------------------------------------------------------------------+------------------|
| MAX_INPUT | number of bytes for which space is available on terminal's input queue | _PC_MAX_INPUT |
|--------------+-------------------------------------------------------------------------+------------------|
| NAME_MAX | maximum number of bytes in a filename (does not include a null at end) | _PC_NAME_MAX |
|--------------+-------------------------------------------------------------------------+------------------|
| PATH_MAX | maximum number of bytes in a relative pathname, including the | _PC_PATH_MAX |
| | terminating null | |
|--------------+-------------------------------------------------------------------------+------------------|
| PIPE_BUF | maximum number of bytes that can be written atomically to a pipe | _PC_PIPE_BUF |
|--------------+-------------------------------------------------------------------------+------------------|
| SYMLINK_MAX | number of bytes in a symbolic link | _PC_SYMLINK_MAX |
+-----------------------------------------------------------------------------------------------------------+
下面更详细地说明这三个函数的不同返回值。
- 如果
name
不是上表中的一个合适的常数,则所有这三个函数都返回-1,并将errno
设置为EINVAL
。 - 有些名称可能或者返回该变量的值(返回值≥O ),或者返回-1,这表示该值是不确定的,此时并不更改
errno
的值。 - 对
_SC_CLK_TCK
的返回值是每秒的时钟滴答数,以用于times
函数的返回值(见8章15节)。
对于 pathconf
的 pahname
参数和 fpathconf
的 filedes
参数,也有一些限制,如果不满足这些限制,将会导致结果不确定,这里不说了,具体参见参考资料。下面代码给出了一个例子:
打印所有的可能 sysconf
和 pathconf
值
#include "apue.h"
#include <errno.h>
#include <limits.h>
static void pr_sysconf(char *, int);
static void pr_pathconf(char *, char *, int);
int
main(int argc, char *argv[])
{
if (argc != 2)
err_quit("usage: a.out <dirname>");
#ifdef ARG_MAX
printf("ARG_MAX defined to be %d\n", ARG_MAX+0);
#else
printf("no symbol for ARG_MAX\n");
#endif
#ifdef _SC_ARG_MAX
pr_sysconf("ARG_MAX =", _SC_ARG_MAX);
#else
printf("no symbol for _SC_ARG_MAX\n");
#endif
/* similar processing for all the rest of the sysconf symbols... */
#ifdef MAX_CANON
printf("MAX_CANON defined to be %d\n", MAX_CANON+0);
#else
printf("no symbol for MAX_CANON\n");
#endif
#ifdef _PC_MAX_CANON
pr_pathconf("MAX_CANON =", argv[1], _PC_MAX_CANON);
#else
printf("no symbol for _PC_MAX_CANON\n");
#endif
/* similar processing for all the rest of the pathconf symbols... */
exit(0);
}
static void
pr_sysconf(char *mesg, int name)
{
long val;
fputs(mesg, stdout);
errno = 0;
if ((val = sysconf(name)) < 0) {
if (errno != 0) {
if (errno == EINVAL)
fputs(" (not supported)\n", stdout);
else
err_sys("sysconf error");
} else {
fputs(" (no limit)\n", stdout);
}
} else {
printf(" %ld\n", val);
}
}
static void
pr_pathconf(char *mesg, char *path, int name)
{
long val;
fputs(mesg, stdout);
errno = 0;
if ((val = pathconf(path, name)) < 0) {
if (errno != 0) {
if (errno == EINVAL)
fputs(" (not supported)\n", stdout);
else
err_sys("pathconf error, path = %s", path);
} else {
fputs(" (no limit)\n", stdout);
}
} else {
printf(" %ld\n", val);
}
}
下面是以上代码运行在本书所基于的、四个平台上面的结果:
一个配置限制的例子
+---------------------------------------------------------------------------------------------------------+
| | | | | Solaris 9 |
| Limit | FreeBSD 5.2.1 | Linux 2.4.22 | Mac OS X 10.3 |------------------------------------|
| | | | | UFS file system | PCFS file system |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| ARG_MAX | 65,536 | 131,072 | 262,144 | 1,048,320 | 1,048,320 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| ATEXIT_MAX | 32 | 2,147,483,647 | no symbol | no limit | no limit |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| CHARCLASS_NAME_MAX | no symbol | 2,048 | no symbol | 14 | 14 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| CHILD_MAX | 867 | 999 | 100 | 7,877 | 7,877 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| clock ticks/second | 128 | 100 | 100 | 100 | 100 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| COLL_WEIGHTS_MAX | 0 | 255 | 2 | 10 | 10 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| FILESIZEBITS | unsupported | 64 | no symbol | 41 | unsupported |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| HOST_NAME_MAX | 255 | unsupported | no symbol | no symbol | no symbol |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| IOV_MAX | 1,024 | no limit | no symbol | 16 | 16 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| LINE_MAX | 2,048 | 2,048 | 2,048 | 2,048 | 2,048 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| LINK_MAX | 32,767 | 32,000 | 32,767 | 32,767 | 1 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| LOGIN_NAME_MAX | 17 | 256 | no symbol | 9 | 9 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| MAX_CANON | 255 | 255 | 255 | 256 | 256 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| MAX_INPUT | 255 | 255 | 255 | 512 | 512 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| NAME_MAX | 255 | 255 | 765 | 255 | 8 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| NGROUPS_MAX | 16 | 32 | 16 | 16 | 16 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| OPEN_MAX | 1,735 | 1,024 | 256 | 256 | 256 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| PAGESIZE | 4,096 | 4,096 | 4,096 | 8,192 | 8,192 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| PAGE_SIZE | 4,096 | 4,096 | no symbol | 8,192 | 8,192 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| PATH_MAX | 1,024 | 4,096 | 1,024 | 1,024 | 1,024 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| PIPE_BUF | 512 | 4,096 | 512 | 5,120 | 5,120 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| RE_DUP_MAX | 255 | 32,767 | 255 | 255 | 255 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| STREAM_MAX | 1,735 | 16 | 20 | 256 | 256 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| SYMLINK_MAX | unsupported | no limit | no symbol | no symbol | no symbol |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| SYMLOOP_MAX | 32 | no limit | no symbol | no symbol | no symbol |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| TTY_NAME_MAX | 255 | 32 | no symbol | 128 | 128 |
|--------------------+---------------+---------------+---------------+-----------------+------------------|
| TZNAME_MAX | 255 | 6 | 255 | no limit | no limit |
+---------------------------------------------------------------------------------------------------------+
译者注
原文参考
6、选项
我们在前面看到了 POSIX.1
的选项,也给出了 XSI
的选项,如果我们想要写的可以移植的程序依赖这些选项,那么我们需要有一个可移植的方法来确定某个实现是否支持指定选项。
相应前面的限制, Single UNIX Specification
定义了三个方式来做到这一点:
- 编译期间的选项定义在
<unistd.h>
中。 - 运行期间的和文件目录无关的选项通过
sysconf
函数来识别。 - 运行期间的和文件目录相关的选项通过
pathconf
或者fpathconf
函数来识别。
具体参见参考资料,这里列出一些选项:
sysconf
的选项和名称参数
+-----------------------------------------------------------------------------------------------------------+
| Name of option | Description | name argument |
|----------------------------+-------------------------------------------------+----------------------------|
| _POSIX_JOB_CONTROL | indicates whether the implementation supports | _SC_JOB_CONTROL |
| | job control | |
|----------------------------+-------------------------------------------------+----------------------------|
| _POSIX_READER_WRITER_LOCKS | indicates whether the implementation supports | _SC_READER_WRITER_LOCKS |
| | readerwriter locks | |
|----------------------------+-------------------------------------------------+----------------------------|
| _POSIX_SAVED_IDS | indicates whether the implementation supports | _SC_SAVED_IDS |
| | the saved set-user-ID and the saved | |
| | set-group-ID | |
|----------------------------+-------------------------------------------------+----------------------------|
| _POSIX_SHELL | indicates whether the implementation supports | _SC_SHELL |
| | the POSIX shell | |
|----------------------------+-------------------------------------------------+----------------------------|
| _POSIX_VERSION | indicates the POSIX.1 version | _SC_VERSION |
|----------------------------+-------------------------------------------------+----------------------------|
| _XOPEN_CRYPT | indicates whether the implementation supports | _SC_XOPEN_CRYPT |
| | the XSI encryption option group | |
|----------------------------+-------------------------------------------------+----------------------------|
| _XOPEN_LEGACY | indicates whether the implementation supports | _SC_XOPEN_LEGACY |
| | the XSI legacy option group | |
|----------------------------+-------------------------------------------------+----------------------------|
| _XOPEN_REALTIME | indicates whether the implementation supports | _SC_XOPEN_REALTIME |
| | the XSI real-time option group | |
|----------------------------+-------------------------------------------------+----------------------------|
| _XOPEN_REALTIME_THREADS | indicates whether the implementation supports | _SC_XOPEN_REALTIME_THREADS |
| | the XSI real-time threads option group | |
|----------------------------+-------------------------------------------------+----------------------------|
| _XOPEN_VERSION | indicates the XSI version | _SC_XOPEN_VERSION |
+-----------------------------------------------------------------------------------------------------------+
fpathconf
的选项和名称参数
+-----------------------------------------------------------------------------------------------------------+
| Name of option | Description | name argument |
|-------------------------+----------------------------------------------------------+----------------------|
| _POSIX_CHOWN_RESTRICTED | indicates whether use of chown is restricted | _PC_CHOWN_RESTRICTED |
|-------------------------+----------------------------------------------------------+----------------------|
| _POSIX_NO_TRUNC | indicates whether pathnames longer than NAME_MAX | _PC_NO_TRUNC |
| | generate an error | |
|-------------------------+----------------------------------------------------------+----------------------|
| _POSIX_VDISABLE | if defined, terminal special characters can be disabled | _PC_VDISABLE |
| | with this value | |
|-------------------------+----------------------------------------------------------+----------------------|
| _POSIX_ASYNC_IO | indicates whether asynchronous I/O can be used with the | _PC_ASYNC_IO |
| | associated file | |
|-------------------------+----------------------------------------------------------+----------------------|
| _POSIX_PRIO_IO | indicates whether prioritized I/O can be used with the | _PC_PRIO_IO |
| | associated file | |
|-------------------------+----------------------------------------------------------+----------------------|
| _POSIX_SYNC_IO | indicates whether synchronized I/O can be used with the | _PC_SYNC_IO |
| | associated file | |
+-----------------------------------------------------------------------------------------------------------+
下图列出一些配置选项,以及我们本文使用的四个系统中这些选项相应的值。
配置选项的例子
+-----------------------------------------------------------------------------------------------------------+
| | | | | Solaris 9 |
| Limit | FreeBSD 5.2.1 | Linux 2.4.22 | Mac OS X 10.3 |----------------------------------|
| | | | | UFS file | PCFS file |
| | | | | system | system |
|-------------------------+---------------+--------------+---------------+----------------+-----------------|
| _POSIX_CHOWN_RESTRICTED | 1 | 1 | 1 | 1 | 1 |
|-------------------------+---------------+--------------+---------------+----------------+-----------------|
| _POSIX_JOB_CONTROL | 1 | 1 | 1 | 1 | 1 |
|-------------------------+---------------+--------------+---------------+----------------+-----------------|
| _POSIX_NO_TRUNC | 1 | 1 | 1 | 1 | unsupported |
|-------------------------+---------------+--------------+---------------+----------------+-----------------|
| _POSIX_SAVED_IDS | unsupported | 1 | unsupported | 1 | 1 |
|-------------------------+---------------+--------------+---------------+----------------+-----------------|
| _POSIX_THREADS | 200112 | 200112 | defined | 1 | 1 |
|-------------------------+---------------+--------------+---------------+----------------+-----------------|
| _POSIX_VDISABLE | 255 | 0 | 255 | 0 | 0 |
|-------------------------+---------------+--------------+---------------+----------------+-----------------|
| _POSIX_VERSION | 200112 | 200112 | 198808 | 199506 | 199506 |
|-------------------------+---------------+--------------+---------------+----------------+-----------------|
| _XOPEN_UNIX | unsupported | 1 | undefined | 1 | 1 |
|-------------------------+---------------+--------------+---------------+----------------+-----------------|
| _XOPEN_VERSION | unsupported | 500 | undefined | 3 | 3 |
+-----------------------------------------------------------------------------------------------------------+
译者注
原文参考
7、特征测试宏
如前面所述,头文件中定义了大量的 POSIX.1
和 XSI
标记。但是大多数的实现也向头文件中添加了不少它们自己的定义。如果我们想要编译一个只依赖那些 POSIX
标记的程序,而且不使用任何和实现相关的定义限制,我们需要定义常量 _POSIX_C_SOURCE
。所有的 POSIX.1
头文件使用这个常量,当定义 _POSIX_C_SOURCE
的时候,排除任何与实现相关的定义。
之前版本的 POSXI.1
标准定义了 _POSIX_SOURCE
常量。这个常量后来在 2001
年的 POSIX.1
中被 _POSIX_C_SOURCE
常量替代。
常量 _POSIX_C_SOURCE
和 _XOPEN_SOURCE
被称作“特性宏”。所有的特性宏以一个下划线开始。当使用它们的时候,一般这样:
cc -D_POSIX_C_SOURCE=200112 file.c
这样编译的C程序,和在程序代码中写了 #define _POSIX_C_SOURCE 200112
再编译的效果一样。
如果使用 Single UNIX Specification
第三个版本的特性,那么我们需要定义 _XOPEN_SOURCE
为 600
,这样和定义 _POSIX_C_SOURCE
为 200112L
的 POSIX.1
功能效果一样。
Single UNIX Specification
定义了 c99
工具作为C编译环境,所以我们可以用如下命令:
$c99 -D_XOPEN_SOURCE=600 file.c -o file
为了打开 gcc
编译器的1999版 ISO C
的扩展功能,我们使用 -std=c99
选项,如下:
$gcc -D_XOPEN_SOURCE=600 -std=c99 file.c -o file
另外一个特性宏是 _ _STDC_ _
,这个宏在C编译器遵从 ISO C
标准的时候会自动被C编译器定义。这允许我们可以写既在 ISO C
又在非 ISO C
编译器下编译的程序。例如,如果想要采用 ISO C
定义的特性,那么如果支持的话,头文件中应该包含类似如下代码:
#ifdef _ _STDC_ _
void *myfunc(const char *, int);
#else
void *myfunc();
#endif
尽管大多数C编译器都支持 ISOC
特性,但是也有一些头文件中使用 __STDC__
特性宏。
译者注
原文参考
8、系统基本数据类型
以前,特定的C数据类型和特定的 UNIX
系统变量相关联。例如,设备的主设备号和次设备号码以前存放在一个16位的短整数类型中,其中的8位用于主设备号码,另外的8位用于次设备号码。但是,许多大的系统中,设备号码的值会多于256个,所以需要一种特定的技术(实际上, solaris
使用32位表示设备号码:14位用于主设备号,18位用于次设备号)。
头文件 <sys/types.h>
定义了一些实现独立的数据类型,被称作系统基本数据类型。大多数这些数据类型也都定义在其他的头文件中。这些数据类型通过C语言的 typedef
关键字,在其头文件中有所定义,大多数以 _t
结束。下图列出了我们本书中遇到的许多系统基本数据类型。
一些通用的系统原始数据类型
+-------------------------------------------------------------------------------------------+
| Type | Description |
|--------------+----------------------------------------------------------------------------|
| caddr_t | core address (Section 14.9) |
|--------------+----------------------------------------------------------------------------|
| clock_t | counter of clock ticks (process time) (Section 1.10) |
|--------------+----------------------------------------------------------------------------|
| comp_t | compressed clock ticks (Section 8.14) |
|--------------+----------------------------------------------------------------------------|
| dev_t | device numbers (major and minor) (Section 4.23) |
|--------------+----------------------------------------------------------------------------|
| fd_set | file descriptor sets (Section 14.5.1) |
|--------------+----------------------------------------------------------------------------|
| fpos_t | file position (Section 5.10) |
|--------------+----------------------------------------------------------------------------|
| gid_t | numeric group IDs |
|--------------+----------------------------------------------------------------------------|
| ino_t | i-node numbers (Section 4.14) |
|--------------+----------------------------------------------------------------------------|
| mode_t | file type, file creation mode (Section 4.5) |
|--------------+----------------------------------------------------------------------------|
| nlink_t | link counts for directory entries (Section 4.14) |
|--------------+----------------------------------------------------------------------------|
| off_t | file sizes and offsets (signed) (lseek, Section 3.6) |
|--------------+----------------------------------------------------------------------------|
| pid_t | process IDs and process group IDs (signed) (Sections 8.2 and 9.4) |
|--------------+----------------------------------------------------------------------------|
| ptrdiff_t | result of subtracting two pointers (signed) |
|--------------+----------------------------------------------------------------------------|
| rlim_t | resource limits (Section 7.11) |
|--------------+----------------------------------------------------------------------------|
| sig_atomic_t | data type that can be accessed atomically (Section 10.15) |
|--------------+----------------------------------------------------------------------------|
| sigset_t | signal set (Section 10.11) |
|--------------+----------------------------------------------------------------------------|
| size_t | sizes of objects (such as strings) (unsigned) (Section 3.7) |
|--------------+----------------------------------------------------------------------------|
| ssize_t | functions that return a count of bytes (signed) (read, write, Section 3.7) |
|--------------+----------------------------------------------------------------------------|
| time_t | counter of seconds of calendar time (Section 1.10) |
|--------------+----------------------------------------------------------------------------|
| uid_t | numeric user IDs |
|--------------+----------------------------------------------------------------------------|
| wchar_t | can represent all distinct character codes |
+-------------------------------------------------------------------------------------------+
通过用这种方式来定义这些数据类型,我们就不用由于各种系统的不同,而向我们的应用程序中加入和实现细节相关的东西,进行编译。我们在本书后面遇到这些数据类型的时候,将会讲述每种数据类型的作用。
译者注
原文参考
9、各个标准之间的冲突
总体来看,这些标准之间相互之间配合是非常好的。但是它们之间也有一些不同,由于 SUSv3
是 POSIX.1
的超集,我们这里主要讲述 ISO C
标准和 POSIX.1
标准之间的差别。
ISO C
定义的函数 clock
返回进程使用的 CPU
时间。这个返回值是 clock_t
类型的,我们需要将它除以一个 CLOCKS_PER_SEC
(定义在 <time.h>
头文件中),得到实际的秒数。 POSIX
定义的 times
函数返回调用进程,以及其所有中止子进程的 CPU
时间以及 clock
时间。所有这些时间值都是 clock_t
类型。 sysconf
函数用来获得每秒的时钟滴答数目( clock ticks per second
)用于 times
函数的返回值。这样,我们所了同样的每秒时钟滴答数目, ISO C
和 POSIX.1
都对它进行了不同的定义。两个标准都是用同样的 clock_t
数据类型来存放这些不同的值。这样的差别在 Solaris
中也可以看到, clock
函数返回微秒数目(因此 CLOCKS_PER_SEC
是1百万分之一),而 sysconf
函数返回的却是100,表示每秒有100个时钟滴答。
另外一个可能有冲突的就是当 ISO C
标准指定一个函数的时候,并没有像 POSIX.1
那样指定。有些函数在 POSIX
环境下(考虑了多进程)和在 ISO C
环境下(很少考虑其所在操作系统的情况)的实现有所不同。然而,为了兼容,许多遵从 POSIX
的系统实现了 ISO C
函数。 signal
函数就是一个例子。如果我们在不知道的情况下使用了 Solaris
提供的 signal
函数(希望写一个可以移植的能够运行在 ISO C
环境和老的 UNIX
系统的代码),那么它所提供的功能可能和 POSIX.1
得 sigaction
函数提供的功能有所不同,这个后面会讲到。
译者注
原文参考
10、总结
过去的20年间,UNIX编程环境的标准化上面发生了许多的事情。我们这里讨论了一些重要的标准,如 ISO C
, POSIX
, Single UNIX Specification
以及它们在我们本书中所涉及到的四个系统中的作用。我们本书所涉及的四个系统即是: FreeBSD
, Linux
, Mac OS X
, 以及 Solaris
。这些标准尝试定义一些特定的参数,这些参数可以随实现而变化,但是我们也看到了这样的局限。我们会随着阅读,看到许多限制和魔术数常量。
网友评论