第 11 章 系统限制与选项 (System Limits and Options)
核心结论
-
三类系统限制:(1) 编译时固定(如
INT_MAX);(2) 运行时不变(runtime invariant,如页大小);(3) 路径相关(pathname variable,如文件名最大长度)。 -
POSIX 最小值:SUSv3 为每个限制定义
_POSIX_XXX_MAX常量作为「最小保证值」;只要限制 ≥ 这个值就算合规。 -
sysconf():查询运行时不变的限制;参数是
_SC_XXX(如_SC_PAGESIZE、_SC_OPEN_MAX、_SC_ARG_MAX)。 -
pathconf()/fpathconf():查询路径相关的限制;参数是
_PC_XXX(如_PC_NAME_MAX、_PC_PATH_MAX);通过 pathname 或 fd 指定文件。 -
Feature Test Macros:
_POSIX_C_SOURCE、_XOPEN_SOURCE、_GNU_SOURCE控制在编译时启用哪些标准的特性;man page 列出所需宏。 -
getconf:命令行工具,对应 sysconf/pathconf;如
getconf NAME_MAX /boot。
|
本章主旨
本章是 Linux 系统编程「可移植性」的核心。理解系统限制的分类、SUSv3 最小值约定、 |
一、核心概念
本章围绕 5 个核心概念展开:从「限制分类」到「查询 API」再到「feature test macros」。
| 概念 | 定义 + 重要性 | 实现提示 |
|---|---|---|
三类限制 |
编译时固定( |
§11.1;<limits.h> 是静态的;sysconf/pathconf 是动态的。 |
POSIX 最小值约定 |
SUSv3 为每个限制定义 |
§11.1;硬编码最小值保证可移植,但无法利用更大的限制。 |
sysconf() |
查询运行时不变的限制;参数 |
§11.2;返回值含义:>0 = 值,-1 且 errno=0 = 不确定,-1 且 errno≠0 = 错误。 |
pathconf()/fpathconf() |
查询路径相关的限制(如文件名长度);参数 |
§11.3;同名文件可能在不同文件系统上有不同限制(如 /boot vs /tmp)。 |
Feature Test Macros |
|
§3.6;必须在 |
二、详细笔记
11.1 系统限制的分类
What:系统限制按「查询时机」和「是否依赖路径」分为三类;不同类型用不同 API 查询。
Why:理解分类才能正确选择查询 API;硬编码限制值(如 NAME_MAX = 14)会失去可移植性。
How:
| 类型 | 特点 | 查询 API |
|---|---|---|
编译时固定 |
在编译时确定(如 |
直接 |
运行时不变 |
系统启动后固定,但可能不定义在 |
|
路径相关 |
因文件系统而异;如文件名长度、路径长度 |
|
运行时可增加 |
可在运行时调高(如 |
|
SUSv3 最小值示例(§11.1 表 11-1):
| 限制 | 最小值 | sysconf 名字 |
|---|---|---|
|
4096 |
|
|
20 |
|
|
8 |
|
|
1 |
|
|
8 |
|
|
32 |
|
|
14 |
|
|
256 |
|
|
512 |
|
命名约定(§11.1):
-
_POSIX_XXX_MAX:SUSv3 规定的最小值(在<limits.h>中)。 -
XXX_MAX:实现提供的实际值(如果定义了)。 -
_SC_XXX:sysconf 的参数名。 -
_PC_XXX:pathconf/fpathconf 的参数名。
When:
-
写可移植代码——使用
sysconf/pathconf查询实际值,不要硬编码。 -
性能优化——查询更大限制,利用优势。
-
调试兼容性——
getconf命令快速检查当前系统值。
Example:
$ getconf NAME_MAX /boot
255
$ getconf NAME_MAX / # 根文件系统(可能不同)
255
$ getconf ARG_MAX
2097152
$ getconf OPEN_MAX
1024
11.2 sysconf() 详解
What:sysconf(name) 查询运行时不变的限制;name 是 _SC_XXX 常量;返回 long 值或 -1。
Why:唯一能在运行时查询限制的标准化 API;-1 含义需小心区分。
How:
// 摘自《The Linux Programming Interface》第 11 章
#include <unistd.h>
long sysconf(int name);
// 返回限制值;-1 表示「不确定」或「错误」
// 通过 errno 区分:调用前 errno=0,调用后
// errno 仍为 0 → 限制不确定
// errno 非 0 → 错误(如 EINVAL = name 非法)
When:
-
启动时查询所有限制——记录在配置或日志。
-
需要 64 位 offset——
sysconf(_SC_FILE_OFFSET_BITS) == 64。 -
分配缓冲区——根据限制值动态决定大小(如
PATH_MAX)。
Example(Listing 11-1):
// 摘自《The Linux Programming Interface》第 11 章 syslim/t_sysconf.c
static void sysconfPrint(const char *msg, int name) {
errno = 0;
long lim = sysconf(name);
if (lim != -1) {
printf("%s %ld\n", msg, lim);
} else {
if (errno == 0)
printf("%s (indeterminate)\n", msg);
else
errExit("sysconf %s", msg);
}
}
int main() {
sysconfPrint("_SC_ARG_MAX: ", _SC_ARG_MAX);
sysconfPrint("_SC_LOGIN_NAME_MAX: ", _SC_LOGIN_NAME_MAX);
sysconfPrint("_SC_OPEN_MAX: ", _SC_OPEN_MAX);
sysconfPrint("_SC_NGROUPS_MAX: ", _SC_NGROUPS_MAX);
sysconfPrint("_SC_PAGESIZE: ", _SC_PAGESIZE);
sysconfPrint("_SC_RTSIG_MAX: ", _SC_RTSIG_MAX);
return 0;
}
11.3 pathconf() 与 fpathconf()
What:pathconf(path, name) 和 fpathconf(fd, name) 查询路径相关的限制;通过 pathname 或已打开的 fd 指定文件。
Why:不同文件系统(ext4、NTFS、NFS)可能有不同限制;查询「特定路径」的限制才是准确的。
How:
// 摘自《The Linux Programming Interface》第 11 章
#include <unistd.h>
long pathconf(const char *path, int name);
// path 必须是该文件系统中存在的路径
// 返回限制值;-1 含义同 sysconf
long fpathconf(int fd, int name);
// 通过已打开的 fd 指定文件
常用 name(_PC_XXX):
-
_PC_NAME_MAX:文件名最大长度(不含 null)。 -
_PC_PATH_MAX:路径名最大长度(含 null)。 -
_PC_PIPE_BUF:管道原子写最大字节数。 -
_PC_LINK_MAX:硬链接最大数。
与 sysconf 的区别:pathconf 路径相关;sysconf 系统范围不变。
When:
-
创建长文件名——先
pathconf(dir, _PC_NAME_MAX)。 -
分配路径缓冲区——
pathconf(dir, _PC_PATH_MAX) + 1。 -
写管道——不能超过
PIPE_BUF,否则可能交错。
Example:
// 摘自《The Linux Programming Interface》第 11 章
long name_max = pathconf("/tmp", _PC_NAME_MAX);
long path_max = pathconf("/tmp", _PC_PATH_MAX);
printf("/tmp: name max = %ld, path max = %ld\n", name_max, path_max);
// 分配 path 缓冲区
char *path = malloc(path_max);
if (path == NULL) errExit("malloc");
11.4 Feature Test Macros
What:Feature test macros 是「特性测试宏」;在 #include 之前定义,控制 <unistd.h> 等头文件暴露哪些声明、常量、类型。
Why:不同 UNIX 标准(POSIX、SUS、XPG)定义了不同的函数子集;通过宏告诉编译器「我要遵循哪个标准」——这是可移植性的基石。
How:常见宏(§3.6):
| 宏 | 暴露的标准 |
|---|---|
典型值 |
|
POSIX |
200809L(POSIX.1-2008) |
|
X/Open + SUS |
500(XPG5)/ 600(SUSv3)/ 700(SUSv4) |
|
GNU 扩展(Linux 特有) |
不需值;等价于 `_BSD_SOURCE |
_SVID_SOURCE` + 上面的所有 |
|
默认行为(含 BSD/SVID) |
不需值 |
|
BSD 风格(已废弃) |
When:
-
写可移植 UNIX 代码——
_POSIX_C_SOURCE=200809L。 -
用 Linux 特有扩展——
_GNU_SOURCE。 -
man page 第 2/3 节的「Feature Test Macro Requirements」会说明所需宏。
Example:
// 摘自《The Linux Programming Interface》第 3 章
// 启用 POSIX.1-2008 和 GNU 扩展
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
// 现在可以使用 O_CLOEXEC、accept4() 等 GNU 扩展
int fd = open("file", O_RDONLY | O_CLOEXEC);
11.5 getconf 命令
What:getconf 命令行工具,对应 sysconf/pathconf;快速查询系统限制。
Why:调试、排查问题时快速知道当前系统限制。
How:
# 摘自《The Linux Programming Interface》第 11 章
# 查询系统限制
$ getconf ARG_MAX
2097152
# 查询路径相关限制(需指定路径)
$ getconf NAME_MAX /boot
255
# 列出所有支持的变量
$ getconf -a
When:
-
排查「为什么我的程序失败」——先
getconf看限制。 -
写可移植构建脚本——
getconf查询值用于编译选项。
三、关键图表
|
非可视化条目(限制查询速查)
|
四、思维导图
mindmap
root((第 11 章 系统限制))
三类限制
编译时
运行时不变
路径相关
运行时可增加
最小值
_POSIX XXX MAX
SUSv3 保证
可移植基础
sysconf
_SC_XXX
long 返回值
errno 区分
pathconf
_PC_XXX
路径相关
fpathconf fd 版
Feature Macros
_POSIX_C_SOURCE
_XOPEN_SOURCE
_GNU_SOURCE
include 前定义
getconf
命令行
调试工具
实际查询
页大小 4096
OPEN_MAX 1024
NAME_MAX 255
PIPE_BUF 512
五、重点与易错点
-
硬编码
NAME_MAX = 14危险:SysV 文件系统是 14,但 ext4/NTFS 是 255;用pathconf查询。 -
sysconf 返回 -1 时区分含义:先
errno = 0,再判断;errno 非 0 是错误,等于 0 是「限制不确定」。 -
pathconf 必须传存在的路径:路径不必存在,但必须位于待查询的文件系统上。
-
_POSIX_C_SOURCE 必须在 #include 前:否则头文件已展开;用编译器选项
-D_POSIX_C_SOURCE=200809L。 -
Linux 2.6+ 实际值远超 POSIX 最小值:OPEN_MAX 可达 1024+;NGROUPS_MAX 可达 65536;不要受最小值约束。
-
_SC_PAGESIZE==_SC_PAGE_SIZE:两者是同义词。 -
某些限制可动态改变:如
OPEN_MAX受RLIMIT_NOFILE影响;ARG_MAX受RLIMIT_STACK影响(详见第 36 章)。 -
getconf 不可移植:不是 POSIX 标准;但 Linux/Solaris/AIX 都有;用于调试。
-
跨章衔接:第 36 章展开资源限制(getrlimit/setrlimit);第 7 章展开 malloc 实现中的限制;本章是基础限制查询。