一.前言
我们在学习《UNIX环境高级编程》这本书,刚开始就会感到晦涩的就是第二章的内容----UNIX标准与实现。
刚开始看确实比较难懂,往往我们会先放一放,后面的很多章节都提到了这方面的内容,等到时候在回顾,或许就会感到霍然开朗!
这本书,我也刚刚看完,感觉还是有很多地方没有掌握,所以在回顾一下,温故而知新嘛。
二.限制
1.哪些限制
为了更好的可移植性,UNIX提供了一些限制,它们定义在头文件<limit.h>中,其中两种限制是必须的:
(1). 编译时限制
(2).运行时限制
编译时限制一般是在头文件中定义的,我们可以通过这样的形式来查看它:
例如:我们要查看ARG_MAX这个限制名在我们的系统中有没有定义,可以这样
#ifdef ARG_MAX
my_arg_max=ARG_MAX;
#endif
而运行时限制则是要求进程调用特定函数以获得此种限制值,一般是使用函数sysconf,pathconf或fpathconf来得到相应的限制值
其中运行时限制的获得有分两种情况:
(1).不与文件或目录相关联的运行时限制:使用函数sysconf
(2).与文件或目录相关联的运行时限制:使用函数pathconf和fpathconf
2.三个和限制有关的函数
这三个函数分别是:
#include <unistd.h>
long sysconf(int name);
long pathconf(const char *pathname,int name);
long fpathconf(int fileds,int name);
返回值:所有函数若成功则返回相应值,若出错则返回-1
第一个函数的参数是一个限制名,后两个函数第一个参数分别是路径和一个文件描述符,第二个参数也是一个限制名
说明:sysconf的限制名name是以_SC开头的符号常量,后两个函数的限制名name是_PC开头的符号常量。
下面我们通过一个函数来具体地说明一下这几个函数的作用吧。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <limits.h> 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 { perror("sysconf"); exit(1); } } } 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 { perror("pathconf"); exit(1); } } //does not setting the errno ,so the system does not //give this var a limit else fputs(" (no limit)/n",stdout); } else printf(" %ld/n",val); } void fatal(char *mes) { perror(mes); exit(1); } int main(int argc,char **argv) { if(argc!=2) { fprintf(stderr,"usage :%s dirname/n",argv[0]); exit(1); } #ifdef ARG_MAX printf("ARG_MAX defined 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 #ifdef MAX_CANON printf("MAX_CANON defined o 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 exit(0); }
三.选项
如果我们需要编写一些可移植的应用程序,而这些应用程序与所有支持的选项相关,那么就需要一种可移植的方法以决定一种实现是否支持一个给定的选项。
Single UNIX Specification定义了三种处理选项的方法:
(1)编译时选项定义在<unistd.h>
(2)与文件或目录无关的选项用sysconf函数确定
(3)与文件或目录相关的选项拥pathconf或fpathconf函数来发现
1.如果平台定义了一些符号常量,我们可以通过它们的值来判断:
(1)如果符号常量的定义值为-1,那么该平台不支持相应的选项
(2)如果符号常量的定义值大于0,那么该平台支持相应的选项
(3)如果符号常量的定义值为0,则必须调用sysconf,pathconf,或fpathconf以确定相应的选项是否受到支持
2.如果平台没有定义这些符号常量,则必须使用前面说的那几个函数来决定该选项是否得到支持。
下面也通过一个函数来具体地说明一下如何得知系统对选项的支持情况。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> void fatal(char *mes) { perror(mes); exit(1); } 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 { perror("sysconf"); exit(1); } } } else printf(" support/n"); } 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 { perror("pathconf"); exit(1); } } //does not setting the errno ,so the system does not //give this var a limit else fputs(" (no limit)/n",stdout); } else printf(" support/n"); } int main(int argc,char **argv) { long val; if(argc!=2) { fprintf(stderr,"usage %s filename/n",argv[0]); exit(1); } #ifdef _POSIX_JOB_CONTROL val=_POSIX_JOB_CONTROL; if(val==-1) printf("The system does't support job control/n"); else if(val>0) printf("THe system supports job control/n"); else pr_sysconf("sysconf: ",_SC_JOB_CONTROL); #else pr_sysconf("sysconf: ",_SC_JOB_CONTROL); #endif #ifdef _POSIX_CHOWN_RESTRICTED val=_POSIX_CHOWN_RESTRICTED; if(val==-1) printf("The file does't support chown/n"); else if(val>0) printf("THe file supports job chown/n"); else pr_pathconf("pathconf: ",argv[1],_SC_JOB_CONTROL); #else pr_pathconf("pathconf: ",argv[1],_SC_JOB_CONTROL); #endif exit(0); }