Day24、错误处理、使用C语言操作环境变量、进程映射、栈的原理(全局、静态变量)

一、错误的处理

根据函数的返回值,来判断函数调用是否出错?

dlopen dlclose dlsym dlerror

在以上这几个函数中,当函数调用出错的时候,通过dlerror函数获取出错的信息

Linux系统调用中或者C语言的库函数中的很多函数在出错的时候,都会设置erron这个全局变量。

errno是一个全局的整型变量,里面存放最近一个函数调用失败的时候产生的错误号,后续可以根据这个错误编号获取错误的详细信息

error 使用error的时候,需要perror函数,需要使用#include<errno.h>头文件

perror(3)

void perror(const char *s);

返回值为空,(注意void和void *的区别)

功能:输出一个错误信息

参数:需要一个字符串

举例:file0.c

  1#include<stdio.h>

  2#include<errno.h>

  3int main(int argc,char *argv[]){

 4     FILE *fp;

 5    fp=fopen("aa.txt","r");

 6     if(NULL==fp){

 7        perror("open");

 8   //    printf("open file failed\n");//这样写不好,找不到错误原因

 9         return 1;

 10     }

 11    fclose(fp);

 12    return 0;

 13 }

执行结果:open : No such file or directory      // 没有aa.txt 这个文件,因此错误提示

 

strerror (3)

#include<string.h>

char *strerror (int errnum);

功能:根据错误号,获取和这个错误编号相符的错误描述信息

参数:错误号

返回值:错误的描述信息

举例:file1.c

  1#include<stdio.h>

  2#include<errno.h>

  3#include<string.h>

  4int main(int argc,char *argv[]){

 5     FILE *fp;

 6    fp=fopen("aa.txt","r");

 7     if(NULL==fp){

 8        printf("%s\n",strerror(errno));

 9         //printf("open filefailed\n");

 10        return 1;

 11     }

 12    fclose(fp);

 13    return 0;

 14 }

tarena@tarena-virtual-machine:~/day24$a.out

No such file or directory

课下思考:printf scanf 库函数原型

 

二、使用C语言操作环境变量

什么是环境变量?

操作系统为程序运行提供的环境参数,即环境变量

程序:程序是静态的,就是放在磁盘里的一个文件。

进程:进程是动态的,进程就是程序运行的实例。

一个文件运行多次就会有多个进程!

每个进程都有独立专属的一个环境变量表,这个环境变量表是从父进程继承来的。

怎么获取这个进程的环境变量?

extern char **environ ; 全局变量

二级指针也是字符串列表

举例:打印当前环境变量

注意:实验环境

  1#include<stdio.h>

  2extern char **environ;   // environ 在系统别的文件已定义好功能,这里引用

  3int main(int argc,char *argv[]){    //*argc[] 是定义了数组指针,即数组里的内容是指针

 4     //由于environ是全局变量,如果对该变量进行改动,有可能引起其他程序的错误

 5     char **env=environ;

 6     while(*env){

 7         printf("%s\n",*env);

 8         env++;

 9     }

 10    return 0;

 11 }

tarena@tarena-virtual-machine:~/day24$a.out

PATH=/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/bin:.

DESKTOP_SESSION=ubuntu-2d

QT_IM_MODULE=xim

PWD=/home/tarena/day24

 

以下是main函数的全貌

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

env是函数的参数,函数的参数是局部变量

是从父进程传过来的环境变量字符串列表

举例打印环境变量:

  1#include<stdio.h>

  2int main(int argc,char *argv[],char *env[]){

 3     while(*env){

 4        printf("%s\n",*env);

 5         env++;

 6     }  

 7     return 0;

  8 }

tarena@tarena-virtual-machine:~/day24$a.out

PATH=/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/bin:.

DESKTOP_SESSION=ubuntu-2d

QT_IM_MODULE=xim

PWD=/home/tarena/day24

 

在自己的进程里,配置环境变量

环境变量的增加、删除、改写、查找、清空

getenv  putenv  setenv  unsetenv clearenv

getenv (3)  man 3 getenv

#include<stdlib.h>

char *getenv ( const char *name ) ;

功能:获取name指定的环境变量的值

参数:name  环境变量的名字

返回值 :返回NULL,代表错误。非NULL值,就是这个环境变量值的地址

举例:getenv.c

  1#include<stdio.h>

  2#include<stdlib.h>

  3int main(int argc,char *argv[]){

 4    printf("%s\n",getenv("PATH"));

 5     return 0;

  6 }

tarena@tarena-virtual-machine:~/day24$./a.out

/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/tarena/workdir/toolchains/opt/S5PV210-crosstools/4.4.6/bin:.

 

putenv(3) 

#include<stdlib.h>

int putenv (char *string) ;

功能:改变或添加环境变量的值

如果指定的环境变量不存在,将这个环境变量添加到环境变量列表里

如果这个环境变量存在,用指定的环境变量的值替换掉原来的值

返回值:0 代表成功   非0代表失败

参数:string   name=value

举例:putenv.c

  1#include<stdio.h>

  2#include<stdlib.h>

  3int main(int argc,char *argv[]){

 4    //printf("%s\n",getenv("PATH"));

  5     //参数的格式  name=value

 6    putenv("TARENA=1000");

 7    printf("%s\n",getenv("TARENA"));

 8     return 0;

  9 }

环境变量是进程的环境变量,是进程的局部变量,在main函数结束的时候,这些变量的内存空间就回收了,即执行完毕,这个进程结束了,环境变量也就消失了。

 

setenv ( 3 )

#include <stdlib.h>

int setenv(const char *name, const char*value, int overwrite);

功能:

参数:

name :环境变量的名字

value :环境变量的值

overwrite:在环境变量列表中已经存在环境变量时,更改环境变量的内容。如果overwrite非0,则更新环境变量的值,如果overwrite是0,则不更新环境变量的值

返回值:

0:成功

-1:失败并且errno变量被设置

 

unsetenv ( 3 )

int unsetenv(const char *name);

功能:从环境变量列表中,将name指定的环境变量删除

参数:name  环境变量的名字

返回值:

0:成功

-1:失败并且errno变量被设置

举例:

  1#include<stdio.h>

  2#include<stdlib.h>

  3int main(int argc,char *argv[]){

 4    //printf("%s\n",getenv("PATH"));

 5     //参数的格式  name=value

 6    putenv("TARENA=1000");

 7     //环境变量存在,不更新环境变量的值

 8    setenv("TARENA","XINJIEKOU",0);

 9     //环境变量存在,更新环境变量的值

 10    setenv("TARENA","NANJING",1);

 11    //环境变量不存在,添加环境变量的值

 12    setenv("TANG","NANJING",1);

 13    unsetenv("TANG");

 14    printf("%s\n",getenv("TARENA"));

 15    getchar();

 16    printf("%s\n",getenv("TANG"));

 17    return 0;

 18 }

tarena@tarena-virtual-machine:~/day24$./a.out

NANJING

1

段错误 (核心已转储)

 

clearenv ( 3 )

#include<stdlib.h>

int clearenv(void)

功能:清除所有的环境变量,即清楚环境变量列表,并且将全局的environ设为NULL。

参数:void

返回值: 0 成功, 非0失败

 

  1#include<stdio.h>

  2#include<stdlib.h>

  3int main(int argc,char *argv[]){

 4    //printf("%s\n",getenv("PATH"));

 5     //参数的格式  name=value

 6    putenv("TARENA=1000");

 7     //环境变量存在,不更新环境变量的值

 8    setenv("TARENA","XINJIEKOU",0);

 9     //环境变量存在,更新环境变量的值

 10    setenv("TARENA","NANJING",1);

 11    //环境变量不存在,添加环境变量的值

 12    setenv("TANG","NANJING",1);

 13    //清除环境变量TANG

 14    unsetenv("TANG");

 15    //清除所有的环境变量

 16    clearenv();

 17    getchar();

 18    printf("%s\n",getenv("TARENA"));

 19    getchar();

 20    printf("%s\n",getenv("TANG"));

 21    return 0;

 22 }

三、进程映射

CPU运行程序

CPU包含:运算器、控制器、存储器

CPU的运算器是处理数据的核心

CPU的运算器访问的是CPU内部的存储部分

CPU内部的存储部分是寄存器

运算器直接访问的是寄存器

32/64位机指运算器一次处理数据的宽度

运算器访问寄存器时,若寄存器里没有运算器需要的数据,则产生中断。有中断服务程序将在cache中查找数据,如果找到,将数据提供给寄存器。如果没找到,产生中断,到内存中区查找。

程序若要运行,必须加载到内存里。

单核CPU举例:进程运行的时候,进程独占CPU

32位机,CPU能访问的地址空间是4G,即每个进程可以访问4G的地址空间

虚拟地址空间 :CPU能访问到的地址编号

物理地址:内存的物理地址

内存管理系统:主要任务是建立虚拟地址空间和物理空间的一个映射关系

在应用程序中操作的地址是虚拟地址

进程映射的概念:

进程映射即进程运行时,虚拟地址空间的布局

图:见笔记本

text 代码段

data 数据段

bss  初始化的数据段

heap  堆

stack  栈   一块内存空间,遵循先进后出的原则

举例:memory.c

  1#include<stdio.h>

  2int main(void){

 3     int var_li=30;

 4     printf("var_li addressis %p\n",&var_li);

 5     getchar();

 6     return 0;

  7 }

执行结果:   var_li address is 0xbfae3bcc

创建新终端   ps  命令查看进程

ps –aux

找到a.out

 

找到进程的身份证号,叫做进程的PID

本进程号为19611

cat  /proc/进程号/maps

找到代码段、数据段、栈

根据变量地址找到栈段,说明 局部变量在栈里。 

举例

  1#include<stdio.h>

  2#include<stdlib.h>

  3int var_gi=30;

  4int var_gi1;

  5void count(void){

  6    static int count=2;

 7     int cou=3;

 8     printf("count++%d\n",count++);

 9     printf("cou++%d\n",cou++);

 10    printf("count address %p\n",&count);

 11    printf("cou address %p\n",&cou);

 12    return ;

 13 }

 14    int main(void){

 15     int i=0;

 16    char *p;

 17    char name[20]="tarena";

 18    char name1[20];

 19    //name1="tarena"; 是错误的,因为上行,name1已经是常量了

 20    //给字符串赋值的时候,用strcpy

 21    char *str="tarena";

 22    int var_li=30;

 23    p=(char *)malloc(1024);

 24     printf("var_liaddress is %p\n",&var_li);

 25    printf("var_gi address is %p\n",&var_gi);

 26    printf("var_gi1 address is %p\n",&var_gi1);

 27    printf("p address is %p\n",&p);

 28    printf("name address is %p\n",name);

 29    printf("str content is %p\n",str);

 30    printf("str address is %p\n",&str);

31     for(i=0;i<=4;i++){

 32        count();

 33     }

 34    getchar();

 35    return 0;

 36 }

 

执行结果:

tarena@tarena-virtual-machine:~/day24$./a.out

var_li address is 0xbfbf75ec

var_gi address is 0x804a020

var_gi1 address is 0x804a030

p address is 0xbfbf75e4

name address is 0xbfbf75f4

str content is 0x8048748

str address is 0xbfbf75e8

count++ 2

cou++ 3

count address 0x804a024

cou address 0xbfbf75bc

count++ 3

cou++ 3

count address 0x804a024

cou address 0xbfbf75bc

count++ 4

cou++ 3

count address 0x804a024

cou address 0xbfbf75bc

count++ 5

cou++ 3

count address 0x804a024

cou address 0xbfbf75bc

count++ 6

cou++ 3

count address 0x804a024

cou address 0xbfbf75bc

 

通过查看Cat/proc/进程号/maps   发现

var_li 在栈里

var_gi 在数据段

var_gi1 在数据段

变量p指向的地址是malloc分配的空间,这块空间在heap(堆)范围内

Char name[20]=“tarena”;

在栈里,为字符数组name开辟了20个字节的内存空间,将字符串的内容拷贝到这块内存空间里。

str 0x8048660 字符串tarena在代码段里

char *str=”tarena”;str变量在栈里,但是str变量的内容指向的是代码段

在函数count里,有两个局部变量cou和count,

count是静态的,内存分配在数据段

cou是自动auto的,内存分配在栈里

 

栈的原理:

栈就是一块内存空间,遵守先进后出的原则

栈帧:每个函数有自己的栈帧,但函数运行完毕的时候,栈帧自动释放,栈帧里存放的就是这个函数的局部变量。

栈的生命周期随着函数的结束而结束

数据段的生命周期随着进程的结束而结束

数据段里的内容不随函数的结束而结束,只在进程结束时数据段里的内容才会释放

(局部变量和静态变量的区别,本质!!  全局变量也在数据段里)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值