APUE (七) :进程环境_每个程序都会接收到一张环境表_amoscykl的博客-程序员秘密

技术标签: APUE  进程  Unix环境高级编程  进程环境  环境  网络编程  

七.进程环境

atexit函数:

函数atexit登记终止处理程序(函数),一个进程最多可以登记32个终止处理函数,这些函数由exit自动调用(return 语句也可以调用),即在程序结束时调用。

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

环境表:

每个程序都会接受到一张环境表。环境表是一个字符指针数组。

全局变量environ包含了该指针数组的地址:

extern char **environ


例如:

环境包含5个字符串,每个字符串结尾处都显式地有一个null字节。environ是环境指针,指针数组为环境表。各指针指向的字符串为环境字符串。



C程序的存储空间布局:

C程序由下列几部分组成:

-正文段。这是由CPU执行的机器指令部分。

-初始化数据段。通常称为数据段。包含了程序中需明确地赋初值的变量。如:int maxcount = 99;

-未初始化数据段。通常称为bss段。如:long sum[1000];

-栈。自动变量以及每次函数调用时所需保存的信息都存放在此段中。

-堆。通常在堆中进行动态存储分配。



size命令可以报告正文段、数据段、和bss段的长度。dec和hex分别表示十进制和十六进制表示的三段总长度


存储空间分布

三个用于存储空间动态分配的函数:


这三个分配函数所返回的指针一定是适当对齐的,使其可用于任何数据对象。


大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息——分配块的长度、指向下一个分配块的指针等。

如果超过一个已分配区的尾端或者在已分配区起始位置之前进行写操作,则会改写另一块的管理记录信息。这样的错误是灾难性的。


其它错误:

-释放一个已释放的块

-若对一个进程调用malloc函数,却忘记调用free函数,那么该进程占用的存储空间就会连续增加,这称为泄漏(C++中new,不delete)


环境变量

函数getenv,可以用其取环境变量值。此函数返回一个指针指向name = value字符串中的value.

———————————————————————————————————————————————————————————


这些函数在修改环境表时是如何进行操作的呢?
答:环境表(指向实际name=value字符串的指针数组)和环境字符串通常存放在进程存储空间的顶部(栈)。

删除一个字符串很简单:先在环境表中找到该指针,然后将所有后续指针都向环境表首部顺次移动一个位置。



———————————————————————————————————————————————————————————


函数setjmp和longjmp

函数setjmp和longjmp执行类型跳转功能


在希望返回到的位置调用setjmp , setjmp参数env的类型是一个特殊类型jmp_buf , 其中存放在调用longjmp时能用来恢复栈状态的所有信息。因为需要在longjmp函数中引用env变量,所以通常将env变量定义为全局变量。


当检查到一个错误时,用两个参数调用longjmp,第一个是setjmp所用的env,第二个参数是个非0的val值,它将成为setjmp函数返回的值。根据返回的值可以判断是从哪个longjmp跳转的,从而判断出程序出错在哪。

#include "apue.h"
#include<setjmp.h>

#define TOK_ADD 5

jmpbuf jmpbuffer;       //声明为全局变量

int main(void)
{
    char line[MAXLINE];
    
    if(setjmp(jmpbuffer) != 0)
        print("error");
    while (fgets(line,MAXLINE,stdin) != NULL)
        do_line(line);
    exit(0);
}
...

void cmd_add(void)
{
    int token;
    
    token = get_token();
    if (token < 0)              //发生错误
        longjmp(jmpbuffer,1);   //设置返回值为1,根据返回值判断发生错误的地方。
}

1.自动变量、寄存器变量和易失变量

问题:在main函数中,自动变量和寄存器变量的状态如何?当longjmp返回到main函数时,这些变量的值能否回复到以前调用setjmp时的值(即回滚原先值)?

答案是:看情况。大多数情况下值是不确定的。如果有个自动变量,而又不想使其回滚,可定义其具有volatile属性。声明为全局变量和静态变量的值在执行longjmp时保持不变。


实例:通过程序说明在调用longjmp后,自动变量,全局变量,寄存器变量,静态变量,易失变量的不同情况。

#include<stdio.h>
#include "apue.h"
#include<setjmp.h>

static void f1(int, int, int, int);
static void f2(void);

static jmp_buf          jmpbuffer;
static int              globval;                        //全局变量

int main(void)
{
        int             autoval;                        //自动变量
        register int    regival;                        //寄存器变量
        volatile int    volaval;                        //易失变量
        static   int    statval;                        //静态变量

        globval = 1; autoval = 2; regival = 3; volaval = 4; statval = 5;

        if (setjmp(jmpbuffer) != 0) {           //直接调用setjmp返回0
                printf("after longjmp:\n");
                printf("globval = %d, autoval = %d, regival = %d, volaval = %d, statval = %d\n",globval,autoval,regival,volaval,statval);
                exit(0);
        }

        /*
         * 在setjmp之后,在longjmp之前。改变各变量的值
         */
        globval = 95; autoval = 96; regival = 97; volaval = 98; statval = 99;

        f1(autoval,regival,volaval,statval);                    //不返回
        exit(0);
}

static void f1(int i, int j, int k, int l)
{
        printf("in f1():\n");
        printf("globval = %d, autoval = %d, regival = %d, volaval = %d, statval = %d\n",globval,i,j,k,l);
        f2();
}

static void f2(void)
{
        longjmp(jmpbuffer,1);
}

gcc testjmp.c            //不进行优化的编译


gcc -O  testjmp.c    //进行优化的编译


全局变量,静态变量,易失变量不受优化的影响,在longjmp之后,它们的值是最近所呈现的值。不能回滚。



函数getrlimit和setrlimit

对这两个函数的每一次调用都指定一个资源以及一个指向下列结构的指针。






版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/amoscykl/article/details/80102243

智能推荐

POJ 1284-Primitive Roots(欧拉函数求原根个数)_求模n原根个数_Rocky0429的博客-程序员秘密

Primitive RootsTime Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64uSubmit Status Practice POJ 1284Appoint description: System Crawler  (2015-04-06)Descripti

python如何下载安装tensorflow_TensorFlow安装和下载(超详细)_weixin_39912368的博客-程序员秘密

本节将介绍在不同的操作系统(Linux、Mac和Windows)上如何全新安装 TensorFlow 1.3。首先了解安装 TensorFlow 的必要要求,TensorFlow 可以在 Ubuntu 和 macOS 上基于 native pip、Anaconda、virtualenv 和 Docker 进行安装,对于 Windows 操作系统,可以使用 native pip 或 Anaconda...

AI 转型必看|算法工程师的 AI 启示录_百度全量车型识别算法是什么_百度大脑的博客-程序员秘密

为降低企业智能化升级过程中技术投入成本高等问题,百度大脑 AI 开放平台不但全面开放 AI 能力,还推出软硬一体解决方案,帮助企业快速实现智能化转型。本月EdgeBoard 车型识别软硬一体方案全新发布,具有识别精度高、计算速度快;适应无网、弱网、高低温等多变的部署环境等优势,适用于智慧交通、智慧停车、园区管理等场景。除此之外,还有多项精彩活动享不停,2021万有引力计划全新发布,飞桨企业版万元专享券免费领;2021年中 Hi 购季精彩来袭!本月还有12项重要产品能力升级、上新、精彩活动,下面就给你带.

关于应用程序出现窗口不完整,GDI对象猛增,GDI资源泄漏的问题的探讨_火星牛的博客-程序员秘密

<br />http://hi.baidu.com/qi_xian/blog/item/08011716e096751e962b4345.html<br />本文转载于3SDN: http://www.3sdn.net<br />有时候,一个应用程序运行到一定的时间,会出现窗口不完整(花屏),出现“必需的资源无法得到”的报错,这是个令人烦恼的问题。此时,你如果打开资源管理器,在“查看”中“选择列”,添加“GDI对象”,可以很清晰得看到,随着程序的运行,GDI对象,快速地增加,当数量达到9999时(为什么是这

Kubernetes 工作负载控制器Controller Deployment_富士康质检员张全蛋的博客-程序员秘密

一个 Pod 被创建出来,不管是由你直接创建,还是由其他工作负载控制器(Workload Controller)自动创建,经过调度器调度以后,就永久地“长”在某个节点上了,直到该 Pod 被删除,或者因为资源不够被驱逐,抑或由于对应的节点故障导致宕机等。因此单独地用一个 Pod 来承载业务,是没办法保证高可用、可伸缩、负载均衡等要求,而且 Pod 也无法“自愈”。这时我们就需要在 Pod 之上做一层抽象,通过多个副本(Replica)来保证可用 Pod 的数量,避免业务不可用。在介绍 Kuberne..

有了 Promise 和 then,为什么还要使用 async?_高先生的猫的博客-程序员秘密

比如说我们需要一段请求服务器的代码:new Promise((resolve, reject) =&gt; { setTimeout(() =&gt; { const res = '明月几时有' if (1 &gt; 2) { resolve(res) } else { reject('我不知道,把酒问青天吧') } }, 1500)}).then( (res) =&gt; { console.log(`成功啦!结果是...

随便推点

BLE之广播参数与广播间隔等说明_ble 广播间隔_zhaoshuzhaoshu的博客-程序员秘密

版权声明:本文为博主原创文章,转载请注明原文出处。 http://blog.csdn.net/zzfenglin/article/details/51165543Advertising interval  (广播间隔)     设备每次广播时,会在3个广播信道上发送相同的报文。这些报文被称为一个广播事件。除了定向报文以外,其他广播事件均可以选择“20ms ~ 10.28s”不等的间隔。通常,一个广...

python flask用户权限管理 接口访问权限思路_flask 权限管理_Jenrey的博客-程序员秘密

1、关于用户权限的几种情况举例:2、解决思路:明确一点我们还是要使用@auth.login_required和@auth.verify_password,因为这样可以把接口不公开暴露我们可以把权限信息写入到token令牌中我们可以把A、B、C、D看做是表,可以写到mysql、redis或者就写到我们的代码里。其实最好是把这种对应关系做成配置文件的形式。那么,我们先给...

常用邮箱SMTP/POP3地址及端口_smtp 端口_凱凱啊的博客-程序员秘密

GMAIL:接收邮件服务器: pop.gmail.com接收端口: 995(必须使用ssl)发送邮件服务器: smtp.gmail.com发送端口: 465(必须使用ssl)或者587(TLS/STARTTLS)IMAP接收邮件服务器: imap.gmail.com接收端口: 993(必须使用ssl)163邮箱(126类似163,参照即可):接收邮件服务器: pop.163.com接收端口: 110或995(使用ssl时)接收邮件服务器: imap.163.com

【PHP】Base64加密解密(可逆)_base64可逆吗_·氓的博客-程序员秘密

1. MD5加密string md5 ( string $str [, bool $raw_output = false ] )参数str--原始字符串。raw_output--如果可选的 raw_output 被设置为 TRUE,那么 MD5 报文摘要将以16字节长度的原始二进制格式返回。这是一种不可逆加密,执行如下的代码$password = '1234...

bootstrap-table 表格加载中....处理_weixin_33895475的博客-程序员秘密

$('#table').bootstrapTable({data:[]});$('#table').bootstrapTable("showLoading");ajax数据加载success$('#table').bootstrapTable("hideLoading");转载于:https://www.cnblogs.com/yzlsthl/p/8378427.html...

阿里云服务器ECS 第一篇:FTP文件服务器搭建_Hello_World_QWP的博客-程序员秘密

云服务器ECS 第一篇:FTP文件服务器搭建目前打算将项目部署到云服务器上,并配置系统运行环境,搭建FTP服务器是系统部署的第一步,从这里开始!!!关于FTP:FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于Internet上的控制文件的双向传输。同时,它也是一个应用程序(Application)。基于不同的操

推荐文章

热门文章

相关标签