UNIX 环境高级编程|UNIX 标准及实现

GitHub: https://github.com/storagezhang

Emai: debugzhang@163.com

华为云社区:https://bbs.huaweicloud.com/blogs/249303

本文为《UNIX 环境高级编程》第 2 章学习笔记

本章对 UNIX 环境编程的 3 个主要标准进行了说明:

  • ISO C
  • POSIX
  • Single UNIX Specification

分析了这些标准对本书主要关注的 4 个实现所产生的影响:

  • FreeBSD
  • Linux
  • Mac OS X
  • Solaris

这些标准都试图定义一些可能随实现而更改的参数,但是这些限制并不完美。

2.2 UNIX 标准化

ISO C

ISO C 标准的意图是提供 C 程序的可移植性,使其能适合于大量的不同的操作系统,而不只是适合 UNIX 系统。

  • 此标准不仅定义了 C 程序设计语言的语法和语义,还定义了标准库。
  • 因为所有现金的 UNIX 系统都提供 C 标准中定义的库函数,所以该标准库非常重要。
头文件 说明
<asert.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> 宽字符分类和映射支持

IEEE POSIX

POSIX 指的是可移植操作系统接口。

  • 该标准的目的是提升应用程序在各种 UNIX 系统环境之间的可移植性。它定义了“符合 POSIX 的” 操作系统必须提供的各种服务。
  • POSIX 1003.1 说明了一个接口而不是一种实现,所以并不区分系统调用和库函数,所有在标准中的例程都被称为函数。
  • 该标准包含了 ISO C 标准库函数。
  • POSIX.1 没有包括超级用户的这样的概念,代之以规定某些操作要求“适当的优先权”。

Single UNIX Specification

Single UNIX Specification 是 POSIX.1 标准的一个超集,它定义了一些附加接口扩展了 POSIX.1 规范提供的功能。

2.3 UNIX 系统实现

标准只是接口的规范,这些标准由厂商采用,然后转变成具体实现。

目前 UNIX 主要有以下实现:

  • SVR4
  • 4.4BSD
  • FreeBSD
  • Linux
  • Mac OS X
  • Solaris

2.5 限制

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

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

  • 编译时限制(短整型的最大值是什么?)
    • 编译时限制可在头文件中定义,程序在编译时可以包含这些头文件。
  • 运行时限制(文件名有多少个字符?)
    • 运行时现状要求进程调用一个函数获得限制值。

某些限制在一个给定的实现中可能是固定的(因此可以静态地在一个头文件中定义),而在另一个实现中则可能是变动的(需要有一个运行时函数调用),这种类型限制的一个例子是文件名的最大字符数。

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

  • 编译时限制(头文件)
  • 与文件或目录无关的运行时限制(sysconf 函数)
  • 与文件或目录有关的运行时限制(oathconffpathconf 函数)

ISO C 限制

ISO C 定义的所有编译时限制都列在头文件 <limits.h> 中,这些限制常量在一个给定系统中并不会改变。

<stdio.h> 头文件还定义了 3 个编译时限制:

  • FOPEN_MAX
    • 保证可同时打开的标准 I/O 流的最小个数,其最小值是 8.
  • TMP_MAX
    • tmpnam 函数产生的唯一文件名的最大个数。
  • FILENAME_MAX
    • 避免使用该常量
    • POSIX.1 提供了更好的替代常量(NAME_MAXPATH_MAX

POSIX 限制

POSIX.1 定义了很多涉及操作系统实现限制的常量,这些限制和常量分成下列 7 类:

  • 数值限制
  • 最小值
  • 最大值
  • 运行时可以增加的值
  • 运行时不变值(可能不确定)
  • 其他不变值
  • 路径名可变值

在这些限制和常量中,某些可能定义在 <limits.h> 中,其余的按具体条件可定义、可不定义。

  • 一个给定进程的实际值可能依赖于系统的存储总量。

这些最小值是不变的,不随系统而改变,它们指定了这些特征最具约束性的值。

函数 sysconfpathconffpathconf

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

#include <unistd.h>

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

参数:

  • name 用于标识系统限制
    • _SC_ 开始的常量用作标识运行时限制的 sysconf 函数所使用的 name 参数
    • _PC_ 开始的常量用作标识运行时限制的 ``pathconffpathconf函数所使用的name` 参数
  • pathname :路径名
  • fd :文件描述符

返回值:

  • 若成功,返回相应值

  • 若出错,返回 -1

    • 如果 name 参数并不是一个合适的常量,还要把 errno 置为 EINVAL
    • 有些 name 会返回一个不确定的值,不确定的值通过返回 -1 来体现,而不改变 errno 的值。

守护进程

守护进程(daemon process)是指在后台运行且不与终端相连接的一种进程。

2.6 选项

如果我们要编写可移植的应用程序,而这些程序可能会依赖于这些可选的支持的功能,那么就需要一种可移植的方法来判断是否支持一个给定的选项。

POSIX.1 定义了 3 种处理选项的方法:

  • 编译时选项定义在 <unistd.h> 中
  • 与文件或目录无关的运行时选项用 sysconf 函数来判断
  • 与文件或目录有关的运行时选项通过调用 pathconffpathconf 函数来判断

如果符号常量未定义,则必须使用 sysconfpathconffpathconf 来判断是否支持该选项:

  • name 参数前缀 _POSIX 必须替换为 _SC_PC
  • 对于以 _XOPEN 为前缀的常量,在构成 name 参数时必须在其前放置 _SC_PC

对于每一个选项,有以下 3 种可能的平台支持状态;

  • 如果符号常量没有定义或者定义值为 -1,那么该平台在编译时并不支持相应选项。
  • 如果符号常量的定义值大于 0,那么该平台支持相应选项。
  • 如果符号常量的定义值为 0,则必须调用 sysconfpathconffpathconf 来判断相应选项是否受到支持。

2.8 基本系统数据类型

头文件 <sys/types.h> 中定义了某些与实现有关的数据类型,它们被称为基本系统数据类型。在头文件中,这些数据类型都是用 C 的 typedef 来定义的,它们绝大多数都以 _t 结尾。用这种方式定义了这些数据类型后,就不再需要考虑因系统不同而变化的程序实现细节。

类型 说明
clock_t 时钟滴答计数器(进程时间)
comp_t 压缩的时钟滴答(POSIX.1 未定义)
dev_t 设备号(主和次)
fd_set 文件描述符集
fpos_t 文件位置
gid_t 数值组 ID
ino_t i 节点编号
mode_t 文件类型,文件创建模式
nlink_t 目录项的链接计数
off_t 文件长度和偏移量(带符号的,如 lseek
pid_t 进程 ID 和进程组 ID(带符号的)
pthread_t 线程 ID
ptrdiff_t 两个指针相减的结果(带符号的)
rlim_t 资源限制
sig_atomic_t 能原子性地访问的数据类型
sigset_t 信号集
size_t 对象(如字符串)长度(不带符号的)
ssize_t 返回字节计数的函数(带符号的,如 readwrite
time_t 日历时间的秒计数器
uid_t 数值用户 ID
wchar_t 能表示所有不同的字符码
posted @ 2021-03-18 11:11  debugzhang  阅读(525)  评论(0编辑  收藏  举报