UNIX 环境编程 Note ( UPDATING )

发布时间 2023-07-31 01:12:11作者: Mojies
知识点
limits.h 中提供的一些宏

和数值相关的一些定义:

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 -- 时区的字节数
sysconf 中提供的一些参数

linux 系统中存在三种基础的配置, sysconf, pathconffpathconf。 这些函数可获取系统中在各个维度对进程做出的限制。通过 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
7 进程环境
进程的启动

进程由内核 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 程序一般由以下几个部分组成:

  1. 正文段: CPU 机器指令部分
  2. 初始化数据段:包含已经初始化的变量,包含初始化值
  3. 为初始化数据段: BSS
  4. 栈:

一般可以通过 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 时区信息
函数 setjumplongjump

goto 语句的局限性在于只能在一个函数内调用,而如果涉及到要跨函数进行 goto 的时候就要用到 setjumplongjump 函数了。

// setjmp.h
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);
函数 getrlimitsetrlimit

该两个函数用于操作进程的一些限制。函数定义如下所示:

// 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 时区信息
tips
  • 如果你想要让你的程序以静态的方式编译,那么可以给 gcc 增加 --static 属性。比如 gcc --static -o helloworld helloworld.c
参考资料
  • 《Unix 环境高级编程》
原创文章,版权所有,转载请获得作者本人允许并注明出处
我是留白;我是留白;我是留白;(重要的事情说三遍)