《UNUX环境高级编程》(7)进程环境

news2024/11/18 11:33:37

1、引言

2、main函数

  • main函数的原型
    /*argc是命令行参数的数目,argv是指向各个指针所构成的数组*/
    int main(int argc,char *argv[]);
    

3、进程终止

  • 有八种方式使进程终止。其中5种是正常,它们是:

    1. 从main函数返回
    2. 调用exit
    3. 调用_exit或_Exit
    4. 最后一个线程从其启动例程返回
    5. 从最后一个线程调用pthread_exit
  • 异常终止有三种方式:

    1. 调用abort
    2. 收到一个信号
    3. 最后一个线程对取消请求做出响应

3.1、退出函数

  • 以下三个函数用于正常终止一个程序

    void _exit(int status); //系统调用,立即进入内核
    void _Exit(int status); //系统调用,立即进入内核
    void exit(int status); //先执行一些清理工作,然后返回内核。
    
    • exit函数总是执行标准I/O库的清理关闭操作,对于所有打开的流调用fclose函数,这会造成输出缓冲中的所有数据被写(冲洗)到文件上。
    • 这三个退出函数都有一个参数,即终止状态(或退出状态)。main函数返回一个整形值与用该值调用exit是等价的。于是在main函数中exit(0);等同于return 0;
    • 当调用这些函数时不带终止状态,或者main执行了一个无返回值的return语句,或者main没有声明返回类型为整形,则进程的终止状态是未定义的。
  • 实例:main执行了一个无返回值的return语句

    /*hello1.c*/
    #include        <stdio.h>
    
    int main()
    {
            printf("hello, world\n");
            return;//无返回值
    }
    

    命令行:

    lh@LH_LINUX:~/桌面/apue.3e/environ$ gcc -o hello hello1.c 
    hello1.c: In function ‘main’:
    hello1.c:6:2: warning: ‘return’ with no value, in function returning non-void
      return;
      ^
    lh@LH_LINUX:~/桌面/apue.3e/environ$ ./hello
    hello, world
    lh@LH_LINUX:~/桌面/apue.3e/environ$ echo $?
    13
    

    对程序进程编译然后运行,可见到其终止码是随机的。注意:$?指明上一次执行命令的返回值,同时回忆一下$#$*$?$0$1…的作用

3.2、atexit函数

  • 一个进程可以登记最多32个函数(一些操作系统实现可能更多)个函数,这些函数将由exit自动调用。我们称这些函数为终止处理程序,通过atexit函数来登记这些函数
    int atexit(void (*function)(void));
    
    • exit调用这些函数的顺序与登记它们的顺序相反,同一函数如果被登记多次也会被调用多次
    • exit函数会先调用各终止处理程序,再fclose所有打开流。然后再调用_exit函数终止进程。
    • 如果程序调用exec函数族,则会清除所有已经注册的终止处理程序。
      在这里插入图片描述
  • 内核使程序执行的唯一方法是调用一个exec函数。进程自愿终止的唯一方法是 显式或隐式(通过exit) 调用_exit_Exit。进程也可以非自愿的由一个信号终止。
  • 实例:使用atexit函数
    #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");
    	/*my_exit1登记了两次,则也会调用两次*/
    	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);//等价于exit(0);
    }
    
    static void
    my_exit1(void)
    {
    	printf("first exit handler\n");
    }
    
    static void
    my_exit2(void)
    {
    	printf("second exit handler\n");
    }
    
    命令行:
    root@LH_LINUX:/home/lh/桌面/apue.3e/environ# ./doatexit 
    main is done
    first exit handler
    first exit handler
    second exit handler
    
    可以看到exit调用这些函数的顺序与登记它们的顺序相反

4、命令行参数

  • 调用exec函数的进程可以将命令行参数传递给新程序。UNIX内核并不查看这些字符串,它们的解释完全取决于各个应用程序,因此需要通过exec将这些参数传递给进程

  • 实例:将所有命令行参数都回显到标准输出上。

    #include "apue.h"
    
    int
    main(int argc, char *argv[])
    {
    	int		i;
    
    	for (i = 0; i < argc; i++)		/* echo all command-line args */
    		printf("argv[%d]: %s\n", i, argv[i]);
    	exit(0);
    }
    

    命令行:

    lh@LH_LINUX:~/桌面/apue.3e/environ$ ./echoarg arg1 arg2 arg3
    argv[0]: ./echoarg
    argv[1]: arg1
    argv[2]: arg2
    argv[3]: arg3
    lh@LH_LINUX:~/桌面/apue.3e/environ$ echo arg1 arg2 arg3
    arg1 arg2 arg3
    

    可以看到可执行文件echoarg将所有命令行参数都打印了出来,而echo程序不会回显第0个参数。注意:argv[argc]是一个空指针。

5、环境表

  • 每一个进程都有一张环境表,该表也是一个字符指针数组,其中每个指针指向一个以null结束的C字符串地址。全局变量environ包含了该指针数组的地址。
    extern char **environ;
    
    在这里插入图片描述
    • 每一个环境变量由name=value形式的字符串构成,其中name字段一般是大写字母组成。
    • 当然也可以通过main函数的第三个参数来访问环境变量(已弃用)
      int main(int argc, char* argv[], char**envp);//envp已弃用,规定应使用全局变量environ
      

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

  • C程序由以下部分组成

    • 正文段(或代码段).text
      由CPU执行的机器指令部分组成(即程序编译之后,编译器会将代码翻译成二进制的机器码,机器码存储在代码段(.text)中)。通常正文段可以共享,所以即使是频繁执行的程序在存储器中也只需有一个副本。并且正文段通常是只读的,以防止程序由于意外而修改其指令。也有可能包含一些只读的常数变量,例如字符串常量等。
    • 初始化数据段.data
      通常将此段称为数据段。用于保存有非0初始值全局变量静态变量。(局部变量保存在栈中)
    • 未初始化数据段.bss
      用于保存没有初始值初值为0的全局变量和静态变量。在程序开始执行之前,内核将此段中的数据初始化为0和空指针。
    • 栈stack
      局部变量与每次函数调用时需要保存的信息存放在stack中。每次函数调用时,其返回地址以及调用者的环境信息(如某些寄存器的值)都存放入栈。然后,最近被调用的函数在栈上为其分配栈帧。递归的原理就是每次调用自身时,就用一个新的栈帧,因此一次函数调用实例中的变量不会影响到另一次函数调用实例中的变量。
    • 堆heap
      通常在堆中进行动态存储分配(malloc)。位于bss和stack中间。
      在这里插入图片描述
  • 可执行文件中还有一些其他类型的段:包含符号表的段;包含调试信息的段;包含动态库链接表的段等。这些部分并不装载到进程执行的程序映像中。

  • 可以看出,未初始化数据段的内容并不存放在磁盘程序文件中。因为内核在程序开始运行前将它们都设置为0。需要存放在磁盘程序文件中的只有正文段和初始化数据段。

7、共享库

  • 共享库使得可执行文件中不再需要包含公用的库函数,而只需在所有进程都可引用的存储区中保存这种库例程的一个副本。
  • 程序第一次执行或者第一次调用某个库函数时,用动态链接方法将程序与共享库函数相链接。这减少了每个可执行文件的长度,但增加了一些运行时间开销。这种时间开销发生在该程序第一次被执行时,或者每个共享库函数第一次被调用时。共享库的另一个优点是可以用库函数的新版本代替老版本而无需对使用该库的程序重新编译(假如参数个数与类型都不变)。
  • 下面展示无共享库方式和使用共享库方式创建可执行文件。
    lh@LH_LINUX:~/桌面/apue.3e/environ$ gcc -static hello1.c
    hello1.c:3:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
     main()
     ^
    lh@LH_LINUX:~/桌面/apue.3e/environ$ ls -l a.out
    -rwxrwxr-x 1 lh lh 912728 77 20:54 a.out
    lh@LH_LINUX:~/桌面/apue.3e/environ$ size a.out
       text	   data	    bss	    dec	    hex	filename
     824102	   7284	   6360	 837746	  cc872	a.out
    lh@LH_LINUX:~/桌面/apue.3e/environ$ gcc hello1.c
    hello1.c:3:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
     main()
     ^
    lh@LH_LINUX:~/桌面/apue.3e/environ$ ls -l a.out 
    -rwxrwxr-x 1 lh lh 8608 77 20:54 a.out
    lh@LH_LINUX:~/桌面/apue.3e/environ$ size a.out 
       text	   data	    bss	    dec	    hex	filename
       1183	    552	      8	   1743	    6cf	a.out
    
    可以发现:使用共享库比不使用时,可执行文件的正文和数据段的长度都显著减少。注意:size()报告正文段、数据段和bss段的长度(以字节文单位),结果的第4列和第5列分别以十进制和十六进制表示的3段总长度。

8、存储空间分配

  • 以下三个函数用于存储空间动态分配(在堆上分配)

    void *malloc(size_t size); //分配指定字节数的存储区,此存储区中的初始值不确定
    void *calloc(size_t nmemb, size_t size); //为指定数量指定长度的对象分配存储空间。该空间中的每一位都初始化为0
    void *realloc(void *ptr, size_t size); //增加或减少以前分配区的长度。当增加长度时,可能需要将以前分配区的内容移到另一个足够大的区域,以便在尾端提供增加的存储区,而新增区的初始值不确定。
    
    void free(void *ptr); //释放ptr指向的存储空间,被释放的空间通常被送入可用存储区池。之后,可在调用上述3个分配函数时再分配这些空间。
    
    
    • realloc函数使我们可以增减以前分配的存储区长度。比如我们在堆上有一个数组,想要扩充该数组的长度,并且在该存储区后有足够的空间可供扩充,则可以在原存储区位置上向高地址方向扩充,无需移动原先数组任何内容。如果在原存储区后没有足够空间,则realloc分配另一个足够大的存储区,将现有数组内容全部复制到新分配的存储区,然后释放原存储区,返回新存储区地址。如果ptr是NULL,则realloc与malloc函数功能相同。

    • 这些分配函数通常底层使用sbrk系统调用。该系统调用扩充或缩小进程的堆。

    • 虽然sbrk可以缩小堆区大小,但是大多数malloc和free的实现都不减少进程的存储空间,释放的空间可供以后再分配,将它们保存在malloc池中而不返回给内核

    • 大多数实现所分配的存储空间比所要求的要稍微大一些,额外的空间用来记录管理信息:分配块的长度、指向下一个分配块的指针等。这意味着如果超过一个已分配区的尾端或者在已分配区起始位置之前进行写操作,则会改写另一块的管理记录信息或其他动态分配对象,这种错误是灾难性的。

    • 致命错误:释放了一个已经释放了的块;调用free时使用的指针不是3个alloc函数的返回值等。

    • 若使用malloc函数在堆上动态分配内存空间但是忘记调用free函数,那么该进程占用的存储空间就会连续增加,这称为内存泄漏。如果不调用free释放不再使用的空间,那么进程地址空间长度会慢慢增加,直至不再有空闲空间。

  • 在栈上分配内存空间

    void *alloca(size_t size);
    
    • 它的调用方式与malloc相同,但是在当前函数的栈帧上分配存储空间而不是在堆中。
    • 优点:当函数返回时自动释放它所使用的栈帧,不用手动free释放
    • 缺点:增加了栈帧的长度,而某些系统的函数在已经被调用后不能增加栈帧长度,于是也不支持alloca函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/729958.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

看一看LRU与LFU

LRU&#xff08;Least recently used&#xff1a;最近最少使用&#xff09;和LFU&#xff08;Least frequently used&#xff1a;最不经常使用&#xff09;&#xff0c;两个都是以链表结构为基础&#xff0c;一般是作为缓存使用&#xff0c;当然&#xff0c;既然是缓存&#xf…

第六章:L2JMobius学习 – 源码讲解网络数据通信

本章节介绍客户端和服务器端的网络数据通信&#xff0c;使用的技术是Java NIO&#xff08;也就是套接字Socket&#xff09;。服务器端和客户端使用Socket通信的原因在于&#xff0c;它是双向的&#xff0c;持久的。也就是说&#xff0c;服务器端可以随时的向客户端发送数据&…

Tomcat7部署war包getshell 漏洞复现

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 漏洞描述02 验证方式03 利用方式04 修复方案 01 漏洞描述 Tomcat支持在后台部署war文件&#xff0c;可以直接将webshell部署到web目录下。其中&#xff0c;欲访问后台&#xff0c;需要对应用户有相…

pycharm如何给一串中文快捷加引号(方法一)

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 门前冷落鞍马稀&#xff0c;老大嫁作商人妇。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python白银群【此类生物】问了一个Pycharm基础的问题&a…

Linux文件管理常用命令补充

&#xff08;该图由AI绘制 关注我 学习AI画图&#xff09; 目录 一、查看文件内容 more分屏显示文件内容&#xff08;了解&#xff09; less分屏显示文件内容&#xff08;重点&#xff09; 二、文件统计命令 1、wc命令 2、du命令 三、文件处理命令 1、find命令 2、gr…

unity相机视角平移一段距离

using System.Collections; using System.Collections.Generic; using UnityEngine;public class ControlCamera : MonoBehaviour {//相机视角焦点平移一段距离//需求 相机视角 内的3D对象A 在视角内平移到屏幕C点 public Vector3 InitCameraPos;// Start is called be…

代码随想录算法训练营第十一天 | 二叉树系列2

二叉树系列2 101 对称二叉树二叉树很重要的一点&#xff1a;确定遍历顺序关于递归代码随想录的代码我的代码(理解后编写) 100 相同的树我的代码 572 另一个树的子树我的代码录友的代码&#xff0c;只用递归&#xff01;&#xff01;&#xff01; 104 二叉树的最大深度重点代码随…

OA办公自动化系统哪个好?办公系统oa排名及对比

一、什么是OA办公自动化系统 OA&#xff08;Office Automation办公自动化&#xff09;是一种将智能化科技应用于企业管理中的应用系统。它可以通过电脑网络、互联网等技术手段&#xff0c;将企业的各种业务流程、各种业务数据进行集成和处理&#xff0c;将各种业务流程和各种业…

winfrom 利用反射 加载窗体(单例)

①新建一个项目, 程序集名称为: AssemblyForm (下面要用到的) ②新建一个Form窗体,窗体名称为: Form1 (下面也要用到), Form1里的代码: using System; using System.Windows.Forms;namespace AssemblyForm {public partial class Form1 : Form{public Form1(){InitializeCo…

web-html的基本用法

web前端代码基本用法 <html> <head><meta charset"utf-8"><!-- charset 属性规定 HTML 文档的字符编码。要是没有规定字符编码的话是有可能乱码的 -->待到秋来九月八&#xff08;head&#xff09;<!-- 头部就是直接写在最上面的文字&…

Css:高级技巧

1.精灵图使用 用ps的切片功能测量图片大小和位置 2.字体图标 3.CSS三角形 4.元素显示隐藏 5.鼠标样式 6.输入框input 轮廓线 7.防止文本域拖拽 8 vertical-align实现行内块和文字垂直居中对齐 9.单行文字溢出省略号显示 10.多行文字溢出省略号显示 11.布局技巧 1.相对定位会压…

实战|如何在Linux 系统上免费托管网站

动动发财的小手&#xff0c;点个赞吧&#xff01; Web 服务器可用于指代硬件和软件&#xff0c;或者两者一起工作。出于本指南的目的&#xff0c;我们将重点关注软件方面&#xff0c;并了解如何在 Linux 机器上托管网站。 Web 服务器是一种通过 HTTP/HTTPS 协议接收并响应客户端…

【算法集训之线性表篇】Day 03

文章目录 题目一思路分析代码实现效果 题目一 从有序顺序表中删除其值在给定值s和t之间(要求s<t)的所有元素&#xff0c;若s或t不合理或者线性表为空&#xff0c;则显示错误信息并退出运行。 思路分析 首先&#xff0c;题目给出数据结构为有序顺序表&#xff0c;故要查找…

B站创建视频分集播放列表

上传视频在B站上创建视频分集列表方法 上传时创建分集列表 1、打开B站 2、登录B站后&#xff0c;点击投稿上传视频。 3、上传视频或把视频直接拖拽到页面里&#xff1b; 4、点击上传第一个视频后页面下会出现一个号的按钮&#xff0c;点击继续上传 &#xff0c;上传视频就…

【Python】Selenium操作cookie实现免登录

文章目录 一、查看浏览器cookie二、获取cookie基本操作三、获取cookie并实现免登录四、封装成函数 一、查看浏览器cookie cookie、session、token的区别&#xff1a; cookie存储在浏览器本地客户端&#xff0c;发送的请求携带cookie时可以实现登录操作。session存放在服务器。…

MybatisPlus逆向生成实体类等

面试中遇到的一道机操题&#xff0c;so simple。 这是里SpringBoot项目&#xff0c;注意你的数据表中只有一个id字段是会生成失败的&#xff01; 添加maven依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter…

虚幻引擎程序化资源生成框架PCG 之 UPCGBlueprintElement源码笔记

UPCGBlueprintElement是PCGGraph中自定义节点的基类&#xff0c;但官方目前还没有给出详细的文档&#xff0c;所以从源代码里找点答案。 文章目录 可覆盖函数&#xff08;Override Functions&#xff09;Excute 和 Excute with ContextLoop Body函数和Loop函数Point Loop Body和…

SpringBoot+ Vue 家乡美食系统

&#x1f495;&#x1f495;作者&#xff1a;程序员徐师兄 个人简介&#xff1a;7 年大厂程序员经历&#xff0c;擅长Java、微信小程序、Python、Android等&#xff0c;大家有这一块的问题可以一起交流&#xff01; 各类成品java毕设 。javaweb&#xff0c;ssh&#xff0c;ssm&…

[期末网页作业]-精仿华为官网10个网页(html+css+js)

经过漫长的期末考试季节&#xff0c;我成功地完成了一个华为官网的仿写项目&#xff0c;并且非常高兴地与大家分享。这个项目包含了10个页面&#xff0c;每一个页面都经过了精心的设计和努力的填充。 首先&#xff0c;我注重了页面的整体布局与设计。借鉴了华为官网的风格&…

Unity3d-UGUI实现的贪食蛇小游戏

按鼠标WASD键来控制蛇的走向。 核心的代码如下&#xff1a; using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.UI;/// 《UGUI贪吃蛇》public class TCS2d : MonoBehaviour {public bool isOver false;public bool isStop…