UNIX环境高级编程学习笔记(八)进程环境

来源:互联网 发布:淘宝网店铺装修宝典 编辑:程序博客网 时间:2024/04/30 04:11

1.main函数

C程序总是从main函数开始执行,其原型是:

int main(int argc, char *argv[]);

其中,argc是命令行参数的数目,argv是指向参数的各个指针所构成的数组。
当内核执行C程序时,在调用main前先调用一个特殊的启动例程。可执行程序文件将此启动例程指定为程序的起始地址——这是由连接编辑器设置的,而连接编辑器由C编译器调用。启动例程从内核取得命令行参数和环境变量值,然后为按上述方式调用main函数做好安排。

内核使程序执行的唯一方法是调用一个exec 函数。

2.进程终止
有8种方式使进程终止,其中:

5种为正常终止:

  • 从 main 返回
  • 调用 exit
  • 调用_exit 或者_Exit
  • 最后一个线程从启动例程返回
  • 从最后一个线程调用 pthread_exit

3种异常终止:

  • 调用abort
  • 接到一个信号
  • 最后一个线程对取消请求做出响应

3.退出函数

#include <stdlib.h>void exit(int status);void _Exit(int status);#include <unistd.h>void _exit(int status);

exit 和 _Exit 由ISO C 说明,_exit 由POSIX.1 说明
退出函数用于正常终止一个程序:_exit 和 _Exit 立即进入内核,exit 则先执行一些清理处理,然后返回内核。3个退出函数都带一个整型参数,称为终止状态。

exit 函数总是执行一个标准I/O库的清理关闭操作:对于所有打开流调用fclose 函数。

4.atexit函数

#include <stdlib.h>int atexit(void (*func)(void));

按照ISO C的规定,一个进程可以登记多至32个函数,这些函数由exit 自动调用,我们称这些函数为终止处理程序,并调用atexit 函数来登记这些函数。

5.命令行参数
当执行一个程序时,调用exec 的进程可将命令行参数传递给该新程序。

6.环境表
每个程序都接收到一张环境表。与参数表一样,环境表也是一个字符指针数组,每个指针包含一个以 null 结尾的C字符串的地址。全局变量 environ 则包含了该指针数组的地址:

extern char **environ

environ 称为环境指针,指针数组为环境表,其中各指针指向的字符串为环境字符串:
这里写图片描述

7.C程序的存储空间布局

  • 正文段:这是由CPU执行的机器指令部分。通常,正文段是只读共享的,在存储器中只需一个副本。
  • 初始化数据段:通常将此段称为数据段,它包含了程序中需要明确赋初值的变量。
  • 未初始化数据段:通常将此段称为 bss 段,意思是”由符号开始的块“,在程序开始执行前,内核将此段中数据初始化为0或空指针。
  • 栈:栈空间向低地址增长。自动变量以及每次函数调用时所需保存的信息都存放在此段中。每次函数调用时,其返回地址、以及调用者的环境信息(例如某些机器寄存器)都存放在栈中。然后,新被调用的函数在栈上为其自动和临时变量分配存储空间。通过以这种方式使用栈, C函数可以递归调用。
  • 堆:通常在堆中进行动态存储分配。由于历史上形成的惯例,堆位于非初始化数据段顶和栈底之间。、

这些段典型的安排方式如下:

8.存储空间分配

ISO C说明了3个用于存储空间动态分配的函数:

#include <stdlib.h>void *malloc(size_t size);void *calloc(size_t nobj, size_t size);void *realloc(void *ptr, size_t newsize);void free(void *ptr);
  • malloc根据所指定的 size 分配空间,成功时返回空间的首址,失败时返回 NULL
  • calloc 分配nobj 个size 大小的连续空间,成功时将该段内存全部清零并返回其首址,失败时返回NULL
  • realloc 为已分配的ptr 重新分配一块大小为 newsize 的空间,并返回其首址,失败时返回NULL
  • free 释放指定的ptr 对应的地址空间。注意:ptr 的值并不会因此变成 NULL,free 成功只说明了此段内存可以重新通过malloc获得,free 后若再次直接访问 ptr 指向的地址是不安全的操作。通过malloc分配而不再使用的堆空间,应尽快通过free 回收以避免内存泄漏

函数 alloca 在栈地址空间中进行分配。

9.环境变量

如同前述,环境字符串的形式是:name=value,UNIX内核并不关心这种字符串的意义,它们的解释完全取决于各个应用程序。例如,shell使用了大量的环境变量。其中某一些在登录时自动设置(如HOME,USER等),有些则由用户设置。我们通常在一个shell起动文件中设置环境变量以控制shell的动作。
ISO C定义了一个函数getenv,此函数返回一个指针,它指向 name=value 字符串中的 value 。

#include <stdlib.h>char* getenv(const char* name);

修改环境表的函数:

#include <stdlib.h>int putenv(const char* str);int setenv(const char* name,const char* value,int rewrite);void unsetenv(const char* name);
  • putenv取形式为name=value的字符串,将其放到环境表中。如果name已经存在,则先删除其原来的定义
  • setenv将name设置为value。如果在环境中name已经存在,那么(a)若rewrite非0,则首先删除其现存的定义;(b)若rewrite为0,则不删除其现存定义(name不设置为新的value,而且也不出错)
  • unsetenv删除name的定义。即使不存在这种定义也不算出错

10.函数 setjmp 和 longjmp

C语言中,goto语句是不能跨越函数的,而执行这种类型跳转功能的是函数setjmp 和 longjmp。这两个函数对于处理发生在很深层嵌套函数调用中的出错情况是非常有用的。

#include <setjmp.h>int setjmp(jmp_buf env);void longjmp(jmp_buf env,int val);
  • setjmp 用于设置一个以 env 为标识的栈定位点。
  • longjmp用于跳转到env 所定位的setjmp函数处,以类似 C 语句 goto(但 goto 只能在函数中进行跳转)的方式继续执行程序,并以val 作为 setjmp的返回值。多个 longjmp跳到一个 setjmp处时,就可以通过返回的不同val 值进行区别。

应注意的是,对于longjmp所到达栈中的局部临时变量和寄存器变量等,不能保证可以回滚到当时的状态,而静态变量与 volatile 类型的变量则保持为最近一次被修改的值。特别的,对于局部自动变量,在生命期过后(函数返回被系统回收)不能被再次引用。

11.函数 getrlimit 和 setrlimit

这两个函数用于查询和更改每个进程的资源限制。

#include <sys/resource.h>int getrlimit(int resource, struct rlimit *rlptr);int setrlimit(int resource, const struct rlimit *rlptr);

在更改资源限制时,需遵循3条规则:

  • 任何一个进程都可以将一个软限制值改为小于或等于其硬限制值
  • 任何一个进程都可降低其硬限制值,但它必须大于或等于其软限制值,这种降低,对于普通用户是不可逆的
  • 只有超级用户进程可以提高其硬限制值
0 0
原创粉丝点击