unix限制

UNIX系统实现定义了很多幻数和常量,其中有很多已被硬编码到程序中,或用特定的技术确定。由于大量标准化工作的努力,已有若干种可移植的方法用以确定这些幻数和具体实现定义的限制。这非常有助于改善UNIX环境下软件的可移植性。
以下两种类型的限制是必需的:
1、编译时限制(例如,短整型的最大值是什么?)
2、运行时限制(例如,文件名有多少个字符?)
编译时限制可在头文件中定义,程序在编译时可以包含这些头文件。但是,运行时限制则要求进程调用一个函数获得限制值。
另外,某些限制在一个给定的实现中可能是固定的(因此可以静态地定义在一个头文件中),而在另一个实现中则可能是变动的(需要有一个运行时函数调用)。这种类型限制的一个例子是文件名的最大字符数。为了解决这类问题,提供了以下3种限制:
1、编译时限制(头文件)。
2、与文件或目录无关的运行时限制(sysconf 函数)。
3、与文件或目录有关的运行时限制(pathconf 和 fpathconf 函数)。
如果一个特定的运行时限制在一个给定的系统中并不改变,则可将其静态地定义在一个头文件中。但是,如果没有将其定义在头文件中,应用程序就必须调用3个conf函数中的一个,以确定其运行时限制。
要如何才能找到一个特定系统实际支持的限制值呢?运行时限制可调用下面三个函数之一获得:

#include <unistd.h>

long sysconf(int name);
long pathconf(const char *pathname, int name); // 用路径名作为参数
long fpathconf(int fd, int name); // 用文件描述符作为参数
/* 所有函数返回值:若成功,返回相应值;若出错,返回 -1 */

sysconf函数的name参数用来标识系统限制,以 _SC_ 开始的常量用作标识运行时限制的syscon参数。下表是sysconf函数所使用的name参数:
[table]
|限制名|说明|name参数|
|ARG_MAX|exec函数的参数最大长度(字节)|_SC_ARG_MAX|
|ATEXIT_MAX|可用atexit函数登记的最大函数个数|_SC_ATEXIT_MAX|
|CHILD_MAX|每个实际用户ID的最大进程数|_SC_CHILD_MAX|
|时钟滴答/秒|每秒时钟滴答数|_SC_CLK_TCK|
|COLL_WEIGHTS_MAX|本地定义文件中可赋予LC_COLLATE顺序关键字项的最大权重数|_SC_COLL_WEIGHTS_MAX|
|DELAYTIMER_MAX|定时器最大超限运行次数|_SC_DELAYTIMER_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|
|RTSIG_MAX|为应用程序预留的实时信号的最大个数|_SC_RTSIG_MAX|
|SEM_NSEMS_MAX|一个进程可使用的信号量最大个数|_SC_SEM_NSEMS_MAX|
|SEM_VALUE_MAX|信号量的最大值|_SC_SEM_VALUE_MAX|
|SIGQUEUE_MAX|一个进程可排队信号的最大个数|_SC_SIGQUEUE_MAX|
|STREAM_MAX|一个_SC_STREAM_MAX进程在任意给定时刻标准I/O流的最大个数。如果定义,必须与FOPEN_MAX有相同值|_SC_STREAM_MAX|
|SYMLOOP_MAX|在解析路径名时,可遍历的符号链接数|_SC_SYMLOOP_MAX|
|TIMER_MAX|每个进程的最大定时器个数|_SC_TIMER_MAX|
|TTY_NAME_MAX|终端设备名长度,包括终止null字节|_SC_TTY_NAME_MAX|
|TZNAME_MAX|时区名中的最大字节数|_SC_TZNAME_MAX|
[/table]
pathconf和fpathconf函数为标识系统限制所使用的name参数如下表:
[table]
|限制名|说明|name参数|
|FILESISEBITS|以带符号整型值表示在指定目录中允许的普通文件最大长度所需的最小位数|_PC_FILESISEBITS|
|LINK_MAX|文件链接计数的最大值|_PC_LINE_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|
|_POSIX_TIMESTAMP_RESOLUTION|文件时间戳的纳秒精度|_PC_TIMESTAMP_RESOLUTION|
|SYMLINK_MAX|符号链接的字节数|_PC_SYMLINK_MAX|
[/table]
现在再来详细地讨论一下这3个函数不同的返回值。
1、若name参数不是一个合适的常量,这3个函数都返回-1,并把errno置为EINVAL。
2、有些name会返回一个变量值(>=0)或者提示该值是不确定的。不确定的值通过返回-1来体现,而不改变errno的值。
3、_SC_CLK_TCK的返回值是每秒的时钟滴答数,用于times函数的返回值。
对于pathconf的参数pathname和fpathconf的参数fd有很多限制。如果不满足以下其中任何一个限制,则结果是未定义的:
1、_PC_MAX_CANON和_PC_MAX_INPUT引用的文件必须是终端文件。
2、_PC_LINK_MAX和_PC_TIMESTAMP_RESOLUTION引用的文件可以是文件或目录。如果是目录,则返回值用于目录本身,而不用于目录内的文件名项。
3、_PC_FILESIZEBITS和_PC_NAME_MAX引用的文件必须是目录,返回值用于该目录中的文件名。
4、_PC_PATH_MAX引用的文件必须是目录。但所指定的目录是工作目录时,返回值是相当路径名的最大长度。
5、_PC_PIPE_BUF引用的文件必须是管道、FIFO或目录。在管道或FIFO情况下,返回值是对所引用的管道或FIFO的限制值。对于目录,返回值是对在该目录中创建的任一FIFO的限制值。
6、_PC_SYMLINK_MAX引用的文件必须是目录。返回值是该目录中符号链接可包含字符串的最大长度。
下面这个程序可用来打印这些限制:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.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){
printf("usage: %s <dirname>", argv[0]);
exit(0);
}

#ifdef ARG_MAX
printf("ARG_MAX defined to be %ld\n", (long)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_CNAON defined to be %ld\n", (long)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
printf("sysconf error\n");
}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
printf("pathconf error, path = %s\n", path);
}else{
fputs(" (no limit)\n", stdout);
}
}else{
printf(" %ld\n", val);
}
}


参考书籍:《UNIX环境高级编程》第二章:UNIX标准及实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值