目录
[单刷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系统提供了一下两种限制:
编译时限制(头文件)
运行时限制:
sysconf
、pathconf
和fpathconf
除了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
结尾,根据系统字长和平台的不同,他们具体的实现空间也不同,但是至少保证了不会因为系统不同而去关注具体实现细节。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。