[单刷APUE系列]第二章——Unix标准及实现

山河永寂

目录

[单刷APUE系列]第一章——Unix基础知识[1]
[单刷APUE系列]第一章——Unix基础知识[2]
[单刷APUE系列]第二章——Unix标准及实现
[单刷APUE系列]第三章——文件I/O
[单刷APUE系列]第四章——文件和目录[1]
[单刷APUE系列]第四章——文件和目录[2]
[单刷APUE系列]第五章——标准I/O库
[单刷APUE系列]第六章——系统数据文件和信息
[单刷APUE系列]第七章——进程环境
[单刷APUE系列]第八章——进程控制[1]
[单刷APUE系列]第八章——进程控制[2]
[单刷APUE系列]第九章——进程关系
[单刷APUE系列]第十章——信号[1]

Unix标准化

Unix编程环境和C程序设计语言是如此的普遍,而且标准化工作做了非常多,但是20世纪80年代Unix版本种类的剧增以及他们差别的扩大导致跨平台移植变得越来越难,很多用户都呼吁对其进行标准化。
Unix标准化有四个,ISO C、IEEE POSIX、Single Unix Specification、FIPS

ISO C

ISO C标准现在由ISO/IEC的C程序设计语言国际标准工作组维护和开发。ISO C标准的意图是提供C程序的可移植性,使其能适应于大量的操作系统。标准不但定义了C程序设计语言的语法,还规定了必备的标准库。
1989年,C程序设计语言的ANSI标准被采纳为国际标准,也是最早的一次标准化过程,目前被称为C89标准
1999年,ISO C标准被更新,在C89的基础上增加了基本数据类型、关键字和一些系统函数,这也是目前主流的C语言编译器标准,即C99标准,是继C89以后的第二个C语言官方标准。自1999年以来,也有3次技术勘误用于修正ISO C标准,分别于2001年、2004年和2007年,2011年还更新了C11标准,但是非常遗憾的是,标准审批和实际生产还是有一定时间延迟,所以C11标准目前还并非主流。
根据ISO C标准,C程序设计语言有24个头文件,目前所有的Unix环境都支持这些头文件。

头文件 说明
<assert.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> 标准输入输出
<stdlib.h> 实用函数库
<string.h> 字符串操作
<tgmath.h> 通用类型数学宏
<time.h> 时间日期支持
<wchar.h> 多字节宽字符支持
<wctype.h> 宽字符分类和映射支持
IEEE POSIX

IEEE POSIX在原书内指的是IEEE 1003.1操作系统接口标准,该标准的1988版本递交给ISO,最终成为了国际标准POSIX.1,而后IEEE 1003.1工作组对其作出很多修订,包括了著名的pthreads多线程接口。POSIX标准不仅包含了ISO C标准函数库,还根据标准要求提供包含了系统调用和库函数的头文件,在这里就不一一列出了。由于POSIX标准只是定义了操作系统接口而非实现,所以并未区分系统调用和库函数。其接口分为两部分,一部分是强制规定必须的部分,而另外一部分是非强制要求的可选部分,

Single Unix Specification

Single Unix Specification是POSIX.1标准的一个超集,它定义了一系列附加接口扩展了POSIX.1的功能,Open Group拥有Unix商标,他们定义了SUS标准,一个系统想要称为Unix系统,就必须实现这些接口,并且通过验收性测试,才能得到Unix商标使用权,其中就包括了Mac OS X系统,而Linux虽然实现了这些接口,但是从未提出过申请,所以Linux没有得到过Unix商标。

FIPS

FIPS是联邦信息处理标准,实际上并没有什么卵用,只是美国政府采购的标准,后来还被撤回了。

限制

在做Unix环境开发时,我们经常遇到跨平台编译的问题,例如:x86_64和x86字长的不同导致的数据类型长度不一致。不同Unix版本对接口实现程度不一致。其中最重要的问题就是编译时限制和运行时限制。
编译时限制我们可以通过在头文件中进行宏定义,然后使用include指令包含这些头文件。也可以向编译器传入-Dmacroname=value传入宏定义参数来动态定义这些限制。
运行时限制则要求进程调用库函数来获得系统内置的参数。
Unix系统提供了一下两种限制:

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

  2. 运行时限制:sysconfpathconffpathconf

除了Unix系统要求的限制,C程序设计语言的ISO C标准也提供了编译时限制,所有的限制都被放在<limits.h>头文件中,但是注意,这些限制的具体值实际上是由Unix系统规定的而不是C语言规定。
例如<inttypes.h>头文件,开发者可以利用它提供的常量、宏和派生类型使其代码与显式指定大小的数据项兼容,而不管编译环境如何。众所周知,由于x86_64和x86之间的区别,整形类型所使用的内存空间是不同的,也就是说,我们很可能滥用整形导致边界溢出的问题,在实际开发中,推荐的方法是使用定长的整形,而不是int和long,而这个文件也包含了格式化字符串所需要的描述参数的宏定义,极大地方便了开发者的使用。
Unix系统标准规定的所有限制只包含两种:POSIX限制和XSI限制,对于开发者来说,这两种限制没有任何区别,都是以同样的方式可以获取。
正如前文所言,限制分为编译时限制和运行时限制,运行时限制可以通过下列三个函数获取

long sysconf(int name);
long pathconf(const char *pathname, int name);
long fpathconf(int fd, int name);

顺便更正一下原著关于fpathconf函数返回值的错误,原著是log,实际上是long。

The pathconf() and fpathconf() functions provides a method for applications to determine the current value of a configurable system limit or option variable associated with a pathname or file descriptor.

非常简单易懂,这两个函数实际上没什么区别,只是用文件描述符来代替文件路径罢了。

     _PC_LINK_MAX
             The maximum file link count.

     _PC_MAX_CANON
             The maximum number of bytes in terminal canonical input line.

     _PC_MAX_INPUT
             The minimum maximum number of bytes for which space is available in a terminal input queue.

     _PC_NAME_MAX
             The maximum number of bytes in a file name.

     _PC_PATH_MAX
             The maximum number of bytes in a pathname.

     _PC_PIPE_BUF
             The maximum number of bytes which will be written atomically to a pipe.

     _PC_CHOWN_RESTRICTED
             Return 1 if appropriate privileges are required for the chown(2) system call, otherwise 0.

     _PC_NO_TRUNC
             Return 1 if file names longer than KERN_NAME_MAX are truncated.

     _PC_VDISABLE
             Returns the terminal character disabling value.

     _PC_XATTR_SIZE_BITS
             Returns the number of bits used to store maximum extended attribute size in bytes.  For example, if the maximum attribute size
             supported by a file system is 128K, the value returned will be 18.  However a value 18 can mean that the maximum attribute size
             can be anywhere from (256KB - 1) to 128KB.  As a special case, the resource fork can have much larger size, and some file system
             specific extended attributes can have smaller and preset size; for example, Finder Info is always 32 bytes.

上面就是pathconf函数族可能获取的值,具体的可以参考<unistd.h>

     _SC_ARG_MAX
             The maximum bytes of argument to execve(2).

     _SC_CHILD_MAX
             The maximum number of simultaneous processes per user id.

     _SC_CLK_TCK
             The frequency of the statistics clock in ticks per second.

     _SC_IOV_MAX
             The maximum number of elements in the I/O vector used by readv(2), writev(2), recvmsg(2), and sendmsg(2).

     _SC_NGROUPS_MAX
             The maximum number of supplemental groups.

     _SC_NPROCESSORS_CONF
             The number of processors configured.

     _SC_NPROCESSORS_ONLN
             The number of processors currently online.

     _SC_OPEN_MAX
             The maximum number of open files per user id.

     _SC_PAGESIZE
             The size of a system page in bytes.

     _SC_STREAM_MAX
             The minimum maximum number of streams that a process may have open at any one time.

     _SC_TZNAME_MAX
             The minimum maximum number of types supported for the name of a timezone.

     _SC_JOB_CONTROL
             Return 1 if job control is available on this system, otherwise -1.

     _SC_SAVED_IDS
             Returns 1 if saved set-group and saved set-user ID is available, otherwise -1.

     _SC_VERSION
             The version of IEEE Std 1003.1 (``POSIX.1'') with which the system attempts to comply.

     _SC_BC_BASE_MAX
             The maximum ibase/obase values in the bc(1) utility.

     _SC_BC_DIM_MAX
             The maximum array size in the bc(1) utility.

     _SC_BC_SCALE_MAX
             The maximum scale value in the bc(1) utility.

     _SC_BC_STRING_MAX
             The maximum string length in the bc(1) utility.

     _SC_COLL_WEIGHTS_MAX
             The maximum number of weights that can be assigned to any entry of the LC_COLLATE order keyword in the locale definition file.

     _SC_EXPR_NEST_MAX
             The maximum number of expressions that can be nested within parenthesis by the expr(1) utility.

     _SC_LINE_MAX
             The maximum length in bytes of a text-processing utility's input line.

     _SC_RE_DUP_MAX
             The maximum number of repeated occurrences of a regular expression permitted when using interval notation.

     _SC_2_VERSION
             The version of IEEE Std 1003.2 (``POSIX.2'') with which the system attempts to comply.

     _SC_2_C_BIND
             Return 1 if the system's C-language development facilities support the C-Language Bindings Option, otherwise -1.

     _SC_2_C_DEV
             Return 1 if the system supports the C-Language Development Utilities Option, otherwise -1.

     _SC_2_CHAR_TERM
             Return 1 if the system supports at least one terminal type capable of all operations described in IEEE Std 1003.2 (``POSIX.2''),
             otherwise -1.

     _SC_2_FORT_DEV
             Return 1 if the system supports the FORTRAN Development Utilities Option, otherwise -1.

     _SC_2_FORT_RUN
             Return 1 if the system supports the FORTRAN Runtime Utilities Option, otherwise -1.

     _SC_2_LOCALEDEF
             Return 1 if the system supports the creation of locales, otherwise -1.

     _SC_2_SW_DEV
             Return 1 if the system supports the Software Development Utilities Option, otherwise -1.

     _SC_2_UPE
             Return 1 if the system supports the User Portability Utilities Option, otherwise -1.

常用的就是这些,另外可能还有一些非标准参数,这里就不在叙述。想必大家也看出来了,以_SC_开头的就是sysconf,以_PC_开头的就是pathconf
关于原著中不确定的运行时限制,原文写的非常啰嗦,实际上没有什么卵用,因为虽然POSIX规定了很多限制,但是很多都没有被实际实现,所以碰到这种情况,只能使用条件编译、循环尝试、错误码判断等hack手段来搞定。

功能测试宏

由于Unix版本众多,各自的实现也不同,几乎每个Unix实现都自带了自定义的功能选项,为了保证只使用POSIX标准规范定义,我们可以使用_POSIX_C_SOURCE宏定义和_XOPEN_SOURCE宏定义,这也被称为功能测试宏。我们可以给C编译器传入-Dmacroname=value的形式,也可以在头文件中设置宏定义。

基本系统数据类型

为了保证跨平台开发使用同样的类型,Unix标准要求系统提供基本数据类型以供开发者使用,这些数据类型都已_t结尾,根据系统字长和平台的不同,他们具体的实现空间也不同,但是至少保证了不会因为系统不同而去关注具体实现细节。

阅读 3.9k

静雅斋
码代码|Minecraft|Node.jser&PHPer|iOS移动端开发者|Web前端码农
2.4k 声望
157 粉丝
0 条评论
2.4k 声望
157 粉丝
文章目录
宣传栏