进程环境中的[apue]那些事儿都是什么?

摘要:atexit 注册的处理器中可以再调 atexit 或 exit 吗?putenv 或 setenv 增加一个环境变量后 environ 指针地址为什么变了?setjmp & longjmp 跨函数跳转后自动变量为什么回退了
main 函数与进程终止 众所周知,main 函数为 unix like 系统上可执行文件的"入口",然而这个入口并不是指链接器设置的程序起始地址,后者通常是一个启动例程,它从内核取得命令行参数和环境变量值后,为调用 main 函数做好安排。main 函数原型为: int main (int argc, char *argv[]); 这是 ISO C 和 POSIX.1 指义的,当然还存在下面几种不太标准的 main 原型: void main (int argc, char *argv[]); void main (void); int main (void); 不带 argc & argv 参数的表示不打算接受命令行参数;void 返回值的表示不打算返回一个结束状态。 进程的结束状态码与 main 的返回值关系如下: main 声明为 int 类型返回值 main 结束前执行了 return x 语句:x main 结束前执行了无参数 return 语句:未定义 (warning: ‘return’ with no value, in function returning non-void) main 结束前执行了 exit(x) 函数:x main 结束前未执行以上语句:未定义 (warning: control reaches end of non-void function) main 结束前未执行以上语句 [-std=c99]:0 main 声明为 void 类型返回值 (warning: return type of ‘main’ is not ‘int’) main 结束前执行了 return x 语句:未定义 (warning: ‘return’ with a value, in function returning void) main 结束前执行了无参数 return 语句:未定义 main 结束前执行了 exit(x) 函数:x main 结束前未执行以上语句:未定义 测试机为 CentOS 7.9,gcc 版本 4.8.5,每一项的 warning 信息就是基于这两个版本测得。未定义的场景中,均返回 25 这个魔数。 开了 -std=c99 后大部分场景没有改善,仅 main 返回值被声明为 int 类型且在结束前没有调用任何 return 或 exit 时 (第 1 项第 4 小项) 发生了显著变化:从未定义变为返回 0。 进程有 8 种终止方式,其中 5 种为正常终止: 从 main 返回 (无论是否有返回值) 调用 exit 调用 _exit 或 _Exit 最后一个线程从其启动例程返回 最后一个线程调用 pthread_exit 另有 3 种为异常终止: 调用 abort 接到一个信号并终止 最后一个线程对取消请求做出响应 下面重点看一下 3 个 exit 函数: #include <unistd.h> void _exit(int status); #include <stdlib.h> void exit(int status); void _Exit(int status); 声明差别不大,_exit 与 _Exit 分别是 POSIX.1 与 ISO C 的标准,不过可以将它们视为等价,都直接进入内核。exit 则在它们的基础上做了一些清理工作,主要包含以下几个方面: 清理线程局部存储 (TLS) 信息 按顺序调用注册的终止处理程序 为所有标准 I/O 库打开的流调用 fclose 函数,这会 flush 缓冲的输出数据 关于标准 I/O 库,请参考之前写的这篇文章:《[apue] 标准 I/O 库那些事儿 》。 有了上面的铺垫,可以这样理解可执行程序的启动例程与 main 之间的关系: ... exit (main (argc, argv)); 即 main 的返回值是直接传递给 exit 的 status 参数作为进程结束状态的。
阅读全文