news 2026/5/23 14:16:43

《UNIX高级环境编程》 第七章 进程环境 读书笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
《UNIX高级环境编程》 第七章 进程环境 读书笔记

一、main函数

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

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

正如前面提到的,argc是命令行参数的数目,argv是指向个参数的指针组成的数组。

当内核执行C程序时,在调用main前先调用一个特殊的启动例程。可执行文件将此例程指定为程序的起始地址--这是由编译器设置的,而连接编译器则由c编译器调用(通常是cc)。启动例程从内核取得命令行参数和环境变量值,然后按上述方式为调用main做好安排

二、进程终止

八种使进程终止的方式:

(1)从main返回(正常终止)

(2)调用exit(正常终止)

(3)调用_exit或_Exit(正常终止)

(4)最后一个线程从启动例程返回(正常终止)

(5)最后一个线程调用pthread_exit(正常终止)

(6)调用abort(异常终止)

(7)接收到信号并终止(异常终止)

(8)最后一个线程取消对请求做出的响应(异常终止)

1.exit函数

区别:_exit和_Exit函数立即进入内核,而exit则先执行一些清理处理(调用执行终止处理程序,关闭所有标准IO流等等),然后进入内核:

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

exit函数总是会调用fclose函数关闭已经打开的标准IO流。

status参数称为终止状态,如果调用时未指定终止状态,或mian执行了一个无返回值的return,或main没有声明返回的类型为整形,则该进程的终止状态使未定义的。可以使用命令:echo $?来打印命令的退出状态码

return 0;等价于exit(0);

2.atexit函数

按照ISO C规定,一个进程可以登记多达32个终止处理函数,调用atexit函数来登记终止处理函数。

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

- atexit函数的参数是一个函数地址,调用时不需要传递任何参数,不期待返回任何值。

- exit调用这些终止处理函数的顺序与登记顺序相反,重复登记一个函数会导致重复调用。

根据ISO C标准,exit首先调用各终止处理函数,然后按需调用fclose。

POSIX.1扩展了ISO C标准,若程序调用了exec家族的一个函数(其作用是在当前程序在exec调用处启动一个新的程序,旧的进程立即终止不再运行),则清除旧程序的所有终止处理函数,然后执行新程序

内核使程序执行的唯一方法是调用一个exec函数。进程资源终止的唯一方法是显式或隐式的调用_exit或_Exit。进程也可以非结缘的由一个信号使其终止。

例:

#include "apue.h" static void my_exit1(void); static void my_exit2(void); int main(void){ if(atexit(my_exit2)!=0) err_sys("can't register my_exit2"); if(atexit(my_exit1)!=0) err_sys("can't register my_exit1"); if(atexit(my_exit1)!=0) err_sys("can't register my_exit1"); printf("main is done\n"); return(0); } static void my_exit1(void){ printf("first exit handler"); } static void my_exit2(void){ printf("Second exit handler"); }

最终打印:

main is done

first exit handler

first exit handler

second exit handleigemei

三、环境表

每个程序都有一个环境表,是一个字符指针数组,其中每个指针包含一个以null结束的c字符串的地址。全局变量environ包含了该指针数组的地址:

extern char **environ;

其中每个字符串结尾都显式的有一个null字符。我们称environ为环境指针,指针数组为环境表。

通常使用getenv和putenv函数来访问特定的环境变量(后面会讲到)

四、C程序的存储空间布局

1.代码段(正文段):储存程序指令,通常正文段是可共享的,所以即使多次调用的程序也只需要保存一个副本即可。正文段只读,防止程序意外修改自身指令。

2.初始化数据段(只读数据段+已初始化的数据段):只读数据段中存储字符串常量、const变量等,已初始化的数据段初始值来自可执行文件(例如c程序中出现在任何函数之外并且已赋初始值的声明)。

3.非初始化数据段(BSS段):在程序开始之前将此段内的数据初始化为0或空指针(例如c程序中出现在任何函数之外并且未赋初始值的声明)。

4.:自动变量(局部变量)以及每次函数调用时所需保存的信息(返回地址即函数结束后返回到哪、调用者环境即保存的寄存器值、传递给函数的参数、局部变量)都存放在此段中。每次调用函数时,返回的地址以及调用者的环境信息都存放在栈中。通过这种方式调用栈,可以递归调用c函数,递归函数每次调用自身时就使用一个新的栈帧,因此一个函数调用实例中的变量及不会影响另一个函数调用实例中的变量(一个栈帧对应一次调用,每个栈帧相互独立)。栈是编译器自动管理的。地址由高向低增长。

5.:进行动态内存分配,由程序员手动管理,地址由低向高增长,容易出现内存碎片、内存泄漏等问题。

典型的地址空间:

- 栈底和堆顶之间有很大的虚地址空间

- 有图中注意到,未初始化的数据段内容并不存放在磁盘上的程序文件中,因为内核在程序开始运行之前将它们都设置为0.需要存放在程序文件中的段只要正文段和初始化数据段。

- size命令查看程序的空间占用情况

五、存储器分配

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

(1)malloc分配指定字节数的存储区,此存储区中的初始值不确定。

(2)calloc为指定数量具有指定长度的对象分配存储空间,该空间中每一位都初始化为0

(3)realloc更改以前分配的长度(可增加或减少)。增加长度时可能会将目标移动到另一个足够大的区域,新增区的初始值不确定。

#include <stdlib.h> void *malloc(size_t size); void *calloc(size_t nobj,size_t size); void *realloc(void *ptr,size_t newsize);//newsize是指新的存储区的长度 //成功则返回非空指针,失败则返回NULL void free(void *ptr);

因为这三个函数都返回通用指针void*,所以如果在程序中包括了stdlib.h库(获得函数原型),则我们将返回指针赋予一个不同类型的指针时,就不需要显式的执行类型强制转换。

什么是内存对齐?

内存对齐是指数据在内存中的起始地址必须是某个值的整数倍,这个值由数据类型决定,这是硬件的要求,不是语言的规定。例如:

char c; // 1字节对齐(任何地址都可以) short s; // 2字节对齐(地址必须是2的倍数) int i; // 4字节对齐(地址必须是4的倍数) double d; // 8字节对齐(地址必须是8的倍数) long long l;// 8字节对齐

malloc返回的指针一定是适当对齐的,可以用于任何数据对象。这句话是什么意思?假设本系统最严格的要求是dobule类型(参考上述例子),为8字节对齐,那么这三个函数返回的指针就会自动对齐到8字节,这样对于char的1字节、short的2字节、int的4字节都可以对齐了,所以我们可以将返回指针赋予任何一个类型的指针。

free释放ptr指向的存储空间。被释放的空间通常被送入可用存储区池,以后可以再次进行动态分配。

realloc可以增加或减少原分配区的长度,例如,如果为一个数组分配存储空间(512),然后再运行过程中填充他,但一段时间后发现原先的长度不够,就可以调用realloc扩充相应空间。需要注意的是,不能使用realloc延长一个静态的数组(我们常用的int arr[10]={0}就是静态分配)

大多数实现所分配的空间比所要求的大一点,这是因为要有额外的空间来记录管理信息(分配块的长度、指向下一个分配块的指针等等)。这会导致一个严重的问题,假如有一个分配块已经写满,而程序继续向其中写入数据,那么数据就会写入下一个分配块的管理信息。

其他致命错误:释放一个已经释放了的块;调用free时所用的指针不是三个alloc函数的返回值等等。开辟的空间忘记释放,这种情况被称为泄露。

alloca函数:它的调用序列与malloc相同,但是它再当前函数的栈帧上分配空间。优点是:当函数返回时,自动释放它所使用的栈帧,不用手动释放。缺点是:alloca函数增加了栈帧的长度,而某些系统在函数已经被调用后就不能再增加栈帧,所以这些系统并不支持alloca函数。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/22 3:53:35

锂电池保护板mos越多越好吗

锂电池保护板中的MOS管并非越多越好&#xff0c;这是一个典型的"边际效益递减"工程问题。MOS管数量需根据电池容量、放电电流、成本预算和空间限制科学配置&#xff0c;盲目堆砌反而可能降低可靠性。一、MOS管在保护板中的核心作用MOS管是保护IC指令的 "肌肉执行…

作者头像 李华
网站建设 2026/5/22 18:51:52

Windows系统文件sxs.dll缺失损坏问题 下载修复

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

作者头像 李华
网站建设 2026/5/22 21:46:01

Windows系统文件tdh.dll缺失找不到情况 下载修复

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

作者头像 李华
网站建设 2026/5/22 7:02:27

10分钟从零搭建Art Design Pro:Vue 3后台管理系统的完整配置手册

10分钟从零搭建Art Design Pro&#xff1a;Vue 3后台管理系统的完整配置手册 【免费下载链接】art-design-pro 这是一个基于 Vue3、TypeScript、Vite 和 Element-Plus 精心打造的后台管理系统模板&#xff0c;专注于用户体验和视觉设计。 项目地址: https://gitcode.com/GitH…

作者头像 李华
网站建设 2026/5/22 14:54:01

《管理沟通的艺术》网课答案2025

文章目录第1讲作业第一章 管理沟通基础--第2讲 沟通的主要方式第一章 管理沟通基础--第3讲 沟通为什么很重要第一章 管理沟通基础--第4讲 沟通并非易事第二章 管理沟通的准备--第5讲 了解你的沟通对象第二章 管理沟通的准备--第6讲 沟通内容设计第二章 管理沟通的准备--第7讲 管…

作者头像 李华