UNIX 环境编程 Note ( UPDATING )
- 知识点
- limits.h 中提供的一些宏
- sysconf 中提供的一些参数
- 基本系统数据类型
- 7 进程环境
- 进程的启动
- 进程的退出
- 环境变量
- 程序空间布局
- 存储空间分配
- 环境变量
- 函数
setjump
和longjump
- 函数
getrlimit
和setrlimit
- tips
- 参考资料
和数值相关的一些定义:
CHAR_BIT, CHAR_MAX, CHAR_MIN, SCHAR_MAX, SCHAR_MIN, UCHAR_MAX, INT_MAX, INT_MIN, UINT_MAX, SHRT_MAX, SHRT_MIN, USHRT_MAX, LONG_MAX, LONG_MIN, ULONG_MAX, LLONG_MAX, LLONG_MIN, ULLONG_MAX, MB_LEN_MAX, // 在一个多字节字符常量中的最大字节数 FOPEN_MAX, // 允许同时打开的文件数 TMP_MAX, FILENAME_MAX, // 文件名长度
和系统运行相关的一些定义:
ARG_MAX -- exec 函数族的参数最大长度 ATEXIT_MAX -- 可用 atexit 函数登记的最大函数个数 CHILD_MAX -- 每个实际用户 ID 子进程最大个数 DELAYTIMER_MAX -- 定时器最大超限运行次数 HOST_NAME_MAX -- gethostname 返回的主机名长度 LOGIN_NAME_MAX -- 登录名最大长度 OPEN_MAX -- 赋予新建文件描述符的最大值 + 1 PAGESIZE -- 系统内存页大小(单位: 字节) RTSIG_MAX -- 为应用程序预留的事实信号的最大个数 SEM_NSEMS_MAX -- 一个进程可使用的信号量最大个数 SEM_VALUE_MAX -- 信号量最大值 SIGQUEUE_MAX -- 一个进程可排队信号的最大个数 STREAM_MAX -- 一个进程一词可打开的标准 I/O 流的最大个数 SYMLOOP_MAX -- 路径解析过程中可访问的符号链接数 TIMER_MAX -- 一个进程的定时器最大个数 TTY_NAME_MAX -- 终端设备名长度,其中包括 null 字节 TZNAME_MAX -- 时区的字节数
linux 系统中存在三种基础的配置, sysconf
, pathconf
和 fpathconf
。 这些函数可获取系统中在各个维度对进程做出的限制。通过 man 手册可以轻松的查阅。
POSIX.1 variables We give the name of the variable, the name of the sysconf() argument used to inquire about its value, and a short description. First, the POSIX.1 compatible values. ARG_MAX - _SC_ARG_MAX The maximum length of the arguments to the exec(3) family of functions. Must not be less than _POSIX_ARG_MAX (4096). CHILD_MAX - _SC_CHILD_MAX The maximum number of simultaneous processes per user ID. Must not be less than _POSIX_CHILD_MAX (25). HOST_NAME_MAX - _SC_HOST_NAME_MAX Maximum length of a hostname, not including the terminating null byte, as returned by gethostname(2). Must not be less than _POSIX_HOST_NAME_MAX (255). LOGIN_NAME_MAX - _SC_LOGIN_NAME_MAX Maximum length of a login name, including the terminating null byte. Must not be less than _POSIX_LOGIN_NAME_MAX (9). NGROUPS_MAX - _SC_NGROUPS_MAX Maximum number of supplementary group IDs. clock ticks - _SC_CLK_TCK The number of clock ticks per second. The corresponding variable is obsolete. It was of course called CLK_TCK. (Note: the macro CLOCKS_PER_SEC does not give information: it must equal 1000000.) OPEN_MAX - _SC_OPEN_MAX The maximum number of files that a process can have open at any time. Must not be less than _POSIX_OPEN_MAX (20). PAGESIZE - _SC_PAGESIZE Size of a page in bytes. Must not be less than 1. PAGE_SIZE - _SC_PAGE_SIZE A synonym for PAGESIZE/_SC_PAGESIZE. (Both PAGESIZE and PAGE_SIZE are specified in POSIX.) RE_DUP_MAX - _SC_RE_DUP_MAX The number of repeated occurrences of a BRE permitted by regexec(3) and regcomp(3). Must not be less than _POSIX2_RE_DUP_MAX (255). STREAM_MAX - _SC_STREAM_MAX The maximum number of streams that a process can have open at any time. If defined, it has the same value as the standard C macro FOPEN_MAX. Must not be less than _POSIX_STREAM_MAX (8). SYMLOOP_MAX - _SC_SYMLOOP_MAX The maximum number of symbolic links seen in a pathname before resolution returns ELOOP. Must not be less than _POSIX_SYMLOOP_MAX (8). TTY_NAME_MAX - _SC_TTY_NAME_MAX The maximum length of terminal device name, including the terminating null byte. Must not be less than _POSIX_TTY_NAME_MAX (9). TZNAME_MAX - _SC_TZNAME_MAX The maximum number of bytes in a timezone name. Must not be less than _POSIX_TZNAME_MAX (6). _POSIX_VERSION - _SC_VERSION indicates the year and month the POSIX.1 standard was approved in the format YYYYMML; the value 199009L indicates the Sept. 1990 revision. POSIX.2 variables Next, the POSIX.2 values, giving limits for utilities. BC_BASE_MAX - _SC_BC_BASE_MAX indicates the maximum obase value accepted by the bc(1) utility. BC_DIM_MAX - _SC_BC_DIM_MAX indicates the maximum value of elements permitted in an array by bc(1). BC_SCALE_MAX - _SC_BC_SCALE_MAX indicates the maximum scale value allowed by bc(1). BC_STRING_MAX - _SC_BC_STRING_MAX indicates the maximum length of a string accepted by bc(1). COLL_WEIGHTS_MAX - _SC_COLL_WEIGHTS_MAX indicates the maximum numbers of weights that can be assigned to an entry of the LC_COLLATE order keyword in the locale definition file. EXPR_NEST_MAX - _SC_EXPR_NEST_MAX is the maximum number of expressions which can be nested within parentheses by expr(1). LINE_MAX - _SC_LINE_MAX The maximum length of a utility's input line, either from standard input or from a file. This includes space for a trailing newline. RE_DUP_MAX - _SC_RE_DUP_MAX The maximum number of repeated occurrences of a regular expression when the interval notation \{m,n\} is used. POSIX2_VERSION - _SC_2_VERSION indicates the version of the POSIX.2 standard in the format of YYYYMML. POSIX2_C_DEV - _SC_2_C_DEV indicates whether the POSIX.2 C language development facilities are supported. POSIX2_FORT_DEV - _SC_2_FORT_DEV indicates whether the POSIX.2 FORTRAN development utilities are supported. POSIX2_FORT_RUN - _SC_2_FORT_RUN indicates whether the POSIX.2 FORTRAN run-time utilities are supported. _POSIX2_LOCALEDEF - _SC_2_LOCALEDEF indicates whether the POSIX.2 creation of locales via localedef(1) is supported. POSIX2_SW_DEV - _SC_2_SW_DEV indicates whether the POSIX.2 software development utilities option is supported. These values also exist, but may not be standard. - _SC_PHYS_PAGES The number of pages of physical memory. Note that it is possible for the product of this value and the value of _SC_PAGESIZE to overflow. - _SC_AVPHYS_PAGES The number of currently available pages of physical memory. - _SC_NPROCESSORS_CONF The number of processors configured. See also get_nprocs_conf(3). - _SC_NPROCESSORS_ONLN The number of processors currently online (available). See also get_nprocs_conf(3).
clock_t comp_t dev_t fd_set fpos_t gid_t ino_t mode_t nlink_t off_t pid_t pthread_t ptrdiff_t rlim_t sig_atomic_t sigset_t size_t ssize_t time_t uid_t wchar_t
进程由内核 exec 调用,而进程的入口函数一般为 main 函数,但是也不一定,编译器一般在编译链接的时候有一个默认链接脚本,这个脚本给的入口函数就是 main 函数。
而启动进程所使用的参数和环境变量是从内核中取得的。
一般退出函数有以下几个:
// stdlib.h -- ISO void exit(int status); void _Exit(int status); // unistd.h-- POSIX.1 void _exit(int status);
如果想在进程推出的时候统一处理一些事情,可以使用 atexit
注册退出函数。 这些函数会在执行 exit 函数的时候执行。 先注册的函数会后执行,而且该功能并不会有去重处理,如果一个函数调用多次,那么这个函数也会执行多次。 一个进程至少可以注册 32 个终止处理函数,不同系统提供的数量不一样。 而且在所有的终止处理函数调用之后才会关闭所有打开的流。 注意,调用 _exit
和 _Exit
可能并不会触发终止处理函数。
// stdlib.h int atexit( void (*func)(void) );
以下是一些小知识点:
- 如果 main 默认整形返回值,而最后一行推出的语句不是 return 语句,那么将采用隐式返回,默认值为 0。 如果其他情况不指定返回值,则返回结果无定义。
- 在 main 函数中调用 return 和调用 exit 是等价的。
每一个程序穷之后都会默认拥有一个全局变量 const char **environ
, 该变量指向一组环境变量字符串,其中格式为 env_name=value
。 该字符串指针数组的最后一个值为 NULL
, 因此你可以根据该特性判断字符串数组否遍历完。
操作环境变量有以下函数: 另外还可以通过 char *getenv(const char *name);
和 int putenv(char *string);
来访问特定的环境变量。
// stdlib.h int setenv(const char *name, const char *value, int overwrite); int unsetenv(const char *name); int putenv(char *string); char *getenv(const char *name); char *secure_getenv(const char *name); int clearenv(void);
C 程序一般由以下几个部分组成:
- 正文段: CPU 机器指令部分
- 初始化数据段:包含已经初始化的变量,包含初始化值
- 为初始化数据段: BSS
- 栈:
- 堆
一般可以通过 size
指令查看可执行文件的分配。
// chrome 浏览器的例子 size ~/bin/chrome.115.0.5790.102/opt/google/chrome/chrome text data bss dec hex filename 212567609 9669428 2722712 224959749 d689d05 /xxx/bin/chrome.115.0.5790.102/opt/google/chrome/chrome
另外在内存空间中可能还会存在其他类型的段,比如:包含符号表的段,包含调试信息的段以及包含动态共享库链接表的段 ...
ISO 中定义了以下几种从堆空间分配内存空间的方法:
// stdlib.h void *malloc(size_t size); void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t size); void *reallocarray(void *ptr, size_t nmemb, size_t size); void free(void *ptr);
注意,realloc 后地址指针可能发生变化,因此,最好不要将 realloc 出来的地址空间的地址赋予其他指针,因为在 realloc 之后可能造成内存越界访问等未知错误。
在使用 xalloc 分配的空间一般是调用 sbrk
分配出来的,因为要管理这些从内核分配出来的存储区域,因此会在分配的内存区域存在一些管理数据。 如果在使用分配区域时发生越界写,可能会造成一些不可预知的问题(比如 SegmentFault, 或者对象的属性值被篡改等 ),但是因为这些错误一般不会马上显示出来,因此很难追查。 所以使用的时候需要格外小心。
为了方便检查内存泄露,越界访问,重复释放等问题,下面有些更加安全的库可以参考:
1. libmalloc 该库除了提供标准的一些内存分配回收函数外还提供了,用于存储空间配置的mallopt
, 和用于统计信息的mallinfo
2. vamalloc 3. quick-fit 分配速度跟快,但是管理结构占用空间更大。 4. jemalloc BSD 8.0 中使用的一个工具。 5. TCMalloc google 开源, Google perftools 中的一个工具。 6. 函数 alloca 从当前函数栈上分配内存,在函数退出时释放。 但是某些平台因为进入函数之后无法变更栈的长度导致该函数不可用,因此在使用前应该先测试一下。
通用的一些环境变量:
变量 | 描述 |
---|---|
COLUMNS | 终端宽度 |
DATEMSK | gatedate 模板文件路径名 |
HOME | home 起始目录 |
LANG | 本地名 |
LC_ALL | 本地名 |
LC_COLLATE | 本地排序名 |
LC_TYPE | 本地字符分类名 |
LC_MESSAGES | 本地消息名 |
LC_MONETARY | 本地货币编辑名 |
LC_TIME | 本地日期,时间格式名 |
LINES | 终端高度 |
LOGNAME | 登录名 |
MSGVERB | fmtmsg 处理消息组成部分 |
NLSPATH | 消息类模板序列 |
PATH | 搜索可执行文件路径名前缀 |
PWD | 当前工作目录的绝对路径 |
SHELL | 用户首选 shell 名 |
TERM | 终端类型 |
TMPDIR | 创建临时文件的路径名 |
TZ | 时区信息 |
setjump
和 longjump
goto 语句的局限性在于只能在一个函数内调用,而如果涉及到要跨函数进行 goto 的时候就要用到 setjump
和 longjump
函数了。
// setjmp.h int setjmp(jmp_buf env); void longjmp(jmp_buf env, int val);
getrlimit
和 setrlimit
该两个函数用于操作进程的一些限制。函数定义如下所示:
// sys/resource.h int getrlimit(int resource, struct rlimit *rlp); int setrlimit(int resource, const struct rlimit *rlp);
具体平台有哪些资源可以更改可以 man getrlimit
查看一下:
在使用该函数的时候需要注意以下三点:
- 设置的 softlimit 一定要小于等于 hardlimit
- 设置的 hardlimit 只能设置得比之前小
- 普通用户 hardlimit 只能设置得更小,不能设置到更大,只有 root 用户才能设置到更大
一般可以操作的限制有如下这些:
变量 | 描述 |
---|---|
COLUMNS | 终端宽度 |
DATEMSK | gatedate 模板文件路径名 |
HOME | home 起始目录 |
LANG | 本地名 |
LC_ALL | 本地名 |
LC_COLLATE | 本地排序名 |
LC_TYPE | 本地字符分类名 |
LC_MESSAGES | 本地消息名 |
LC_MONETARY | 本地货币编辑名 |
LC_TIME | 本地日期,时间格式名 |
LINES | 终端高度 |
LOGNAME | 登录名 |
MSGVERB | fmtmsg 处理消息组成部分 |
NLSPATH | 消息类模板序列 |
PATH | 搜索可执行文件路径名前缀 |
PWD | 当前工作目录的绝对路径 |
SHELL | 用户首选 shell 名 |
TERM | 终端类型 |
TMPDIR | 创建临时文件的路径名 |
TZ | 时区信息 |
- 如果你想要让你的程序以静态的方式编译,那么可以给 gcc 增加 --static 属性。比如
gcc --static -o helloworld helloworld.c
- 《Unix 环境高级编程》
![]() |
![]() |