APUE笔记:UNIX Standardization and Implementations(二)

本文记录《UNIX环境高级编程》第3版 第2章UNIX标准与实现 的一些知识点。


所有标准化工作的一个重要部分是规定每种环境实现必须定义的各种限制。

UNIX Standardization

ISO C

ISO C标准的目的是确保符合标准的C程序能够移植到多种操作系统上,而不仅仅是UNIX系统。该标准不仅定义了这门编程语言的语法和语义,还定义了一个标准库。

IEEE POSIX

POSIX是由IEEE最初制定的一系列标准。POSIX代表可移植操作系统接口。它最初仅指IEEE 1003.1-1988标准——操作系统接口,但后来扩展到包含许多带有1003编号的标准和标准草案,包括shell和实用程序(1003.2)。

本书特别关注的是1003.1操作系统接口标准,其目标是促进应用程序在各种UNIX系统环境之间的可移植性。

由于1003.1标准规定的是接口而非实现,因此系统调用和库函数之间没有区别。该标准中的所有例程都被称为函数。

The Single UNIX Specification

The Single UNIX Specification, a superset of the POSIX.1 standard, specifies additional interfaces that extend the functionality provided by the POSIX.1 specification. POSIX.1 is equivalent to the Base Specifications portion of the Single UNIX Specification.

Only XSI-conforming implementations can be called UNIX systems.

总结与比较

维度 ISO C POSIX SUS(Single UNIX Specification)
定义主体 国际标准化组织(ISO) 电气电子工程师协会(IEEE) The Open Group(继承自 X/Open)
核心目标 统一 C 语言本身的语法、标准库,确保跨编译器兼容 统一类 Unix 系统的接口,确保应用跨系统兼容 定义“合规 Unix 系统”的完整标准,整合并扩展 POSIX
覆盖范围 C 语言语法(如关键字、类型)、标准库(如 stdio.hstdlib.h 系统调用(如 openfork)、命令行工具(如 ls)、Shell 接口等 包含 POSIX 全部内容,新增更多接口(如 XSI 扩展)、命令和库函数
强制性 编译器需完全实现以声称“符合 ISO C 标准” 系统可部分实现(标记为“可选”),但需声明支持范围 若声称“符合 SUS”,必须实现所有规定内容(包括 POSIX 可选部分中的 XSI 必选接口)
与 Unix 关联 不绑定特定操作系统,适用于所有支持 C 的平台 专为类 Unix 系统设计(如 Linux、macOS) 直接定义“Unix 系统”的标准,是“Unix 商标”认证的依据
典型内容 printfmallocstrcmp 等语言级函数 readwriteexec 等系统调用;pthread 线程库 包含 POSIX 内容 + XSI 扩展(如 msgctl 消息队列、nl_langinfo 本地化函数)
  • ISO C 是“语言标准”,POSIX 是“类 Unix 系统接口标准”,SUS 是“Unix 系统的完整标准”(基于 POSIX 并扩展,更严格)。
  • 一个符合 SUS 的系统,必然符合 POSIX 和 ISO C;但符合 POSIX 或 ISO C 的系统,未必符合 SUS。

UNIX System Implementations

UNIX System V Release 4

4.4BSD

FreeBSD

Linux

Mac OS X

Solaris


限制

UNIX 系统实现定义了很多幻数和常量,其中有很多已被硬编码到程序中,或用特定的技术确定。

以下两种类型的限制是必需的。

(1)编译时限制(例如,短整型的最大值是什么?)

(2)运行时限制(例如,文件名有多少个字符?)

编译时限制可在头文件中定义。程序在编译时可以包含这些头文件。但是,运行时限制则要求进程调用一个函数获得限制值。

此外,某些限制在特定的实现中可能是固定的——因此可以在头文件中静态定义——但在另一种实现中可能会有所不同,这就需要调用运行时函数。

为了解决这类问题,提供了以下3种限制。

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

(2)与文件或目录无关的运行时限制(sysconf函数)。

(3)与文件或目录有关的运行时限制(pathconffpathconf函数)。

函数sysconf、pathconf和fpathconf

运行时限制可调用下面3个函数之一获得。

1
2
3
4
5
#include <unistd.h>
long sysconf(int name);
long pathconf(const char *pathname, int name);
long fpathconf(int fd, int name);
// 所有函数返回值:若成功,返回相应值;若出错,返回-1

具体返回值可参考下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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)
{
// set errno to EINVAL if the name isn’t one of the appropriate constants.
if (errno == EINVAL)
fputs(" (not supported)\n", stdout);
else
err_sys("pathconf error, path = %s", path);
}
// An indeterminate value is indicated by returning −1 and not changing the value of errno.
else
fputs(" (no limit)\n", stdout);
}
// return the value of the variable (a return value ≥ 0)
else
printf(" %ld\n", val);
}

Feature Test Macros

除了POSIX.1和XSI定义的符号外,大多数实现还可以在这些头文件中添加自己的定义。如果想要编译一个程序,使其仅依赖于POSIX定义,且不与任何实现定义的常量发生冲突,就需要定义_POSIX_C_SOURCE这个常量。所有的POSIX.1头文件都会使用这个常量,当_POSIX_C_SOURCE被定义时,就会排除任何实现自己定义的内容。

两种使用方式:

  1. cc -D_POSIX_C_SOURCE=200809L file.c 这会导致特性测试宏在C程序包含任何头文件之前被定义。
  2. 也可以将源文件的第一行设置为 #define _POSIX_C_SOURCE 200809L

要启用《单一UNIX规范》第4版的XSI选项,需要将常量 _XOPEN_SOURCE 定义为700。除了启用XSI选项外,就POSIX.1功能而言,这与将 _POSIX_C_SOURCE 定义为 200809L 具有相同的效果。


基本系统数据类型

头文件<sys/types.h>中定义了某些与实现有关的数据类型,它们被称为基本系统数据类型。还有很多这种数据类型定义在其他头文件中。在头文件中,这些数据类型都是用C的typedef来定义的。它们绝大多数都以_t结尾。

 一些常用的基本系统数据类型