一、错误的处理
根据函数的返回值,来判断函数调用是否出错?
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的,内存分配在栈里
栈的原理:
栈就是一块内存空间,遵守先进后出的原则
栈帧:每个函数有自己的栈帧,但函数运行完毕的时候,栈帧自动释放,栈帧里存放的就是这个函数的局部变量。
栈的生命周期随着函数的结束而结束
数据段的生命周期随着进程的结束而结束
数据段里的内容不随函数的结束而结束,只在进程结束时数据段里的内容才会释放
(局部变量和静态变量的区别,本质!! 全局变量也在数据段里)