2.2UNIX标准化
2.2.1 ISO C
国际标准化组织(International Organization for Standardization,ISO)
国际电子技术委员会(International Electrotechnical Commission,IEC)
ISO C标准的意图是提供C程序的可移植性,使其能适合于大量不同的操作系统,而不只是UNIX系统。此标准不仅定义了C程序设计语言的语法和语义,还定义了其标准库。因为所有现今的UNIX系统都提供C标准中定义的库例程,所以该标准库是很重要的
按照该标准定义的各个头文件,可将ISO C库分成24个区。
ISO C标准定义的头文件:
<asser.h>:验证程序断言
<complex.h>:支持复数算术运算
<ctype.h>:字符类型
<errno.h>:出错码
<fenv.h>:浮点环境
<float.h>:浮点常量
<inttypes.h>:整型格式转换
<iso646.h>:替代关系操作符宏
<limits.h>:实现常量
<locale.h>:局部类别
<math.h>:数字常量
<setjmp.h>:非局部goto
<signal.h>:信号
<stdarg.h>:可变参数表
<stdbool.h>:布尔类型的值
<stddef.h>:标准定义
<stdint.h>整型
<stdio.h>标准I/O库
<stdlib.h>实用程序函数
<string.h>字符串操作
<tgmath.h>:通用类型数学宏
<time.h>:时间和日期
<wchar.h>:扩展的多字节和宽字节支持
<wctype.h>:宽字符分类和映射支持
2.2.2 IEEE POSIX
POSIX是一些列由IEEE(Institute of Electrical and Electronics Engineers,电气与电子工程师协会)制定的标准。POSIX指的是可移植的操作系统接口。他原来只是IEEE标准1003.1-1988(操作系统接口),后来扩展称包括很多标记为1003的标准及标准草案,包括shell和实用程序(1003.2)
1003.1操作系统接口标准,该标准的目的是提高应用程序在各种UNIX系统环境的可移植性。它定义了“依从POSIX的”操作系统必须提供的各种服务。该标准已被大多数计算机制造商采用。虽然1003.1标准是以UNIX操作系统为基础的,但是它并不限于UNIX和类UNIX的系统。确实,有些供应专有操作系统的制造商也声称这些系统将依从POSIX(同时还保有他们的所有专有功能)
由于1003.1标准定义了一个接口而不是一种实现,所以并不区分系统调用和库函数。标准中的所有例程都称为函数
POSIX标准定义的必须的头文件(26项)
<dirent.h> ---------------------- 目录项
<fcntl.h> ---------------------- 文件控制
<fnmatch.h> ---------------------- 文件名匹配类型
<glob.h> ---------------------- 路径名模式匹配类型
<grp.h> ---------------------- 组文件
<netdb.h> ---------------------- 网络数据库操作
<pwd.h> ---------------------- 口令文件
<regex.h> ---------------------- 正则表达式
<tar.h> ---------------------- tar归档值
<termios.h> ---------------------- 终端I/O
<unistd.h> ---------------------- 符号常量
<utime.h> ---------------------- 文件时间
<wordexp.h> ---------------------- 字扩展类型
<arpa/inet.h> ---------------------- Internet定义
<net/if..h> ---------------------- 套接字本地接口
<netinet/in.h> ---------------------- Internet地址族
<netinet/tcp.h> ---------------------- 传输控制协议定义
<sys/mman.h> ---------------------- 内存管理声明
<sys/select.h> ---------------------- select函数
<sys/socket.h> ---------------------- 套接字接口
<sys/stat.h> ---------------------- 文件状态
<sys/times.h> ---------------------- 进程时间
<sys/types.h> ---------------------- 基本系统数据类型
<sys/un.h> ---------------------- UNIX域套接字定义
<sys/utsname.h> ----------------------系统名
<sys/wait.h> ---------------------- 进程控制
POSIX标准定义的XSI扩展头文件(26项)
<cpio.h> ---------------------- cpio归档值
<dlfcn.h> ---------------------- 动态链接
<fmtmsg.h> ---------------------- 消息显示结构
<ftw.h> ---------------------- 文件树漫游
<iconv.h> ---------------------- 代码集转换实用程序
<langinfo.h> ---------------------- 语言信息常量
<libgen.h> ---------------------- 模式匹配函数定义
<monetary.h> ---------------------- 货币类型
<ndbm.h> ---------------------- 数据库操作
<nl_types.h> ---------------------- 消息类别
<poll.h> ---------------------- 轮询函数
<search.h> ---------------------- 搜索表
<strings.h> ---------------------- 字符串操作
<syslog.h> ---------------------- 系统出错日志记录
<ucontext.h> ---------------------- 用户上下文
<ulimit.h> ---------------------- 用户限制
<utmpx.h> ---------------------- 用户帐户数据库
<sys/ipc.h> ---------------------- IPC
<sys/msg.h> ---------------------- 消息队列
<sys/resource.h>------------------- 资源操作
<sys/sem.h> ---------------------- 信号量
<sys/shm.h> ---------------------- 共享存储
<sys/statvfs.h> ---------------------- 文件系统信息
<sys/time.h> ---------------------- 时间类型
<sys/timeb.h> ---------------------- 附加的日期和时间定义
<sys/uio.h> ---------------------- 矢量I/O操作
POSIX标准定义的可选头文件(8项)
<aio.h> ---------------------- 异步I/O
<mqueue.h> ---------------------- 消息队列
<pthread.h> ---------------------- 线程
<sched.h> ---------------------- 执行调度
<semaphore.h> --------------------- 信号量
<spawn.h> ---------------------- 实时spawn接口
<stropts.h> ---------------------- XSI STREAMS接口
<trace.h> ---------------------- 时间跟踪
POSIX.1没有包括超级用户这样的概念,代之以规定某些操作要求“适当的特权”,
2.2.3 Single UNIX Specification
Single UNIX Specification是POSIX.1标准的超集,定义了一些附加的接口,这些接口扩展了基本的POSIX.1规范的功能。相应的系统接口全集被称为X/Open系统接口(XSI,X/Open System Interface) ,XSI还定义了实现必须支持的POSIX.1的哪些可选部分才能认为是遵循XSI的。它们包括文件同步,存储映射文件,存储保护及线程接口。只有遵循XSI的实现才能称为UNIX操作系统。
2.2.4 FIPS
FIPS的含义是联邦信息处理标准(Federal Information Procesing Standard).
POSIX.1 FIPS的影响是:它要球任何希望向美国政府销售POSIX.1兼容的计算机系统的厂商应支持POSIX.1的某些可选功能。因为POSIX.1 FIPS的影响郑逐步减退,所以在本书中我们将不再进一步考虑它
2.3 UNIX系统实现
SVR4
4.4BSD
FreeBSD
Linux
Mac OS X
Solaris
2.5限制
编译时限制可在头文件中定义,程序在编译时可以包含这些头文件。但是,运行时限制则要求进程调用一个函数以获得此种限制值
另外,某些限制在一个给定的实现中可能是固定的(因此可以静态地在一个头文件中定义),而在另一个实现上则可能变化的(需要有一个运行时函数调用)
为解决这类问题,提供以下三种限制:
1.编译时限制(头文件)
2.不与文件或目录相关联的运行时限制(sysconf函数)
3.与文件或目录相关联的运行时限制(pathconf和fpathconf函数)
使事情变得更加复杂的是,如果一个特定的运行时限制在一个给定的系统上并不改变,则可将其静态地定义在一个头文件中,但是,如果没有将其定义在头文件中,则应用程序必须调用三个conf函数中的一个,以确定其运行的值
2.5.1 ISO C限制
ISO C定义的限制都是编译时限制。
2.5.2 POSIX限制
POSIX.1定义了很多涉及操作系统实现限制的常量,不幸的是,这是POSIX.1中最令人迷惑不解的部分之一
1.不变的最小值
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,STREAN_MAXS,SYMLOOP_MAX,TTY_NAME_MAX以及TZNAME_MAX
5.路径名可变值(可能不确定):FILESIZEBITS,LINK_MAX,MAX_CANON,MAX_INPUT,NAME_MAX,PATH_MAX,PIPE_BUF
以及SYMLINK_MAX
2.5.3 XSI限制
XSI还定义了处理实现限制的下面几个常量:
1.不变最小值:NL_ARGMAX,NL_LANGMAX,NL_MSGMAX,NL_NMAX,NL_SETMAX,NL_TEXTMAX,NZERO,_XOPEN_IOV_MAX,_XOPEN_NAME_MAX,_XOPEN_PATH_MAX
2.数值限制:LONG_BIT
和WORD_BIT
3.运行时不变值(可能不确定):ATEXIT_MAX,IOV_MAX
以及PAGE_SIZE
2.5.4 sysconf,pathconf和fpathconf函数
运行时限制可通过调用下面三个函数中的一个而取得
#include <unistd.h>
long sysconf(int name);
long pathconf(const char *pathname,int name);
long fpathconf(int filedes,int name);
以SC开始的常量用作标识运行时限制的sysconf参数。以PC开始的常量用作标识运行时限制的pathconf或fpathconf参数
对于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._PA_PIPE_BUF
所引用的文件必须是管道,FIFO或目录。在管道或FIFO情况下,返回值是对所引用的管道或FIFO的限制值。对于目录,返回值是对该目录中创建的任意FIFO的限 制值
6._PC_SYMLINK_MAX
所引用的文件必须是目录。返回值是该目录中符号链接可能包含的字符串的最大长度
程序清单2_2 打印所有可能的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
#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
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);
}
}
2.5.5 不确定的运行时限制
前面已提及某些限制值可能是不确定的。我们遇到的问题是:如果这些限制值没有在头文件中定义,那么在编译时也就不能使用它们。但是,如果它们的值是不确定的,那么在运行时它们可能也是未定义的
处理不确定结果这种情况的正确方法与如何使用所分配的存储空间有关。例如,如果我们为getcwd调用分配空间(返回当前工作目录的绝对路径名),如果分配空间太小,则返回一个出错,并将errno设置为ERANGE。然后可调用realloc来增加分配的空间并重试。不断重复此操作,直到getcwd调用成功执行
程序清单2_3 为路径名动态地分配空间
#include"apue.h"
#include<errno.h>
#include<limits.h>
#ifdef PATH_MAX
static int pathmax=PATH_MAX;
#else
static int pathmax=0;
#endif
#define SUSV3 200112L
static long posix_version=0;
#define PATH_MAX_GUESS 1024
char* path_alloc(int *sizep)
{
char *ptr;
int size;
if(posix_version==0)
posix_version=sysconf(_SC_VERSION);
if(pathmax==0){
errno=0;
if((pathmax=pathconf("/",_PC_PATH_MAX))<0){
if(errno ==0)
pathmax=PATH_MAX_GUESS;
else
err_sys("pathconf error for _PC_PATH_MAX");
}
else{
pathmax++;
}
}
if(posix_version < SUSV3)
size=pathmax;
if((ptr=malloc(size))==NULL)
err_sys("malloc error for pathname");
if(sizep!=NULL)
*sizep=size;
return(ptr);
}
2.8 基本系统数据类型
头文件<sys/types.h>
中定义了某些与实现有关的数据类型,他们被称为基本系统数据类型(primitive system data type)。还有很多定义在其他头文件中。
基本数据类型
clock_t 时钟滴答计数器(进程时间)
comp_t 压缩的时间滴答
dev_t 设备号(主和次)
fd_set 文件描述符集
fpos_t 文件位置
gid_t 数值组ID
ino_t i节点编号
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 返回字节计数的函数(带符号的)
time_t 日历时间的秒计数器、
uid_t 数值用户ID
wchar_t 能表示所有不同的字符码