[C++系列] UNIX系统高级编程 day04. 动态加载 内存管理 程序中错误处理
in C/C++ with 0 comment

[C++系列] UNIX系统高级编程 day04. 动态加载 内存管理 程序中错误处理

in C/C++ with 0 comment

复习

一,动态库的选择
二,C语言
指针类型。 数据类型

int  p;
Int  *p;
Int. **p;
Int. *p[3];
Int  (*p)[3];
Int. (*p)(void);
Int (*p[4])(void);

三,使用typedef为类型定义别名
1 2 3步
数组类型 diy的类型
函数类型
四,gdb调试器的使用

补充:

动态加载

Malloc(3) 库函数

程序运行的时候,变量的空间一般由系统提供,但有的时候需要在程序中主动向系统提出内存空间的申请,系统为
满足程序的需要为程序分配内存空间,这就是动态分配内存空间。

在可执行程序加载到内存的时候,系统会自动加载可执行程序依赖的动态库。但有的情况下,在程序中可以向系统申请加载需要的动态库,这就是动态加载。

为了实现动态加载库文件,系统提供了一系列动态链接加载的函数。

Dlopen(3)

#include <dlfcn.h>

void* dlopen(const char* filename,int mode);

功能:加载动态库文件

参数:

Filename: 指定了要加载的动态库的文件名
Flag:
RTLD_LAZY : 只有引用的函数被执行的时候才链接。
RTLD_NOW: 在函数返回的时候,所有程序中的引用被链接。

返回值
NULL。 错误
not NULL。 成功

Char *dlerror(void);

功能:返回最近一次函数dlopen,dlsy m,dlclose 调用产生的错误信息。
参数:void
返回值:返回一个字符串,这个字符串描述了错误的原因。
NULL. 没有错误

Void *dlsym(void *handle,const char *symbol);

功能:在指定的动态库里 找函数。

参数
Handle: dlopen(3) 返回值
Symbol: 指定了符号(函数)的名字。

返回值
返回symbol符号加载到内存里的地址。
找不到函数就返回NULL

Int Dlclose(void *handle);

功能: 使动态库的引用计数减一

参数
handle:指定了动态库的地址。dlopen(3)的返回值

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

练习:

  1 #include<stdio.h>
  2 #include<dlfcn.h>
  3 int main(){
  4         //动态加载库函数libsmath.so
  5         void *h = dlopen("libmath.so",RTLD_NOW);
  6         if(h==NULL){
  7         //      printf("load library error ...\n");
  8                 printf("%s\n",dlerror());
  9                 return -1;
10         }
11         printf("load success ...\n");
12         //关闭动态加载
13         dlclose(h);
14         return 0;
15 }
~```
~```

  1 #include<stdio.h>
  2 #include<dlfcn.h>
 #include<pmath.h>
  3 int main(){
  4         //动态加载库函数libsmath.so
  5         void *h = dlopen("libmath.so",RTLD_NOW);
  6         if(h==NULL){
  7         //      printf("load library error ...\n");
  8                 printf("%s\n",dlerror());
  9                 return -1;
10         }
11         printf("load success ...\n”);
         P = (fund_t)dlsym(h,”psub”);
         If(p==null){
             Printf(“%s\n”,dlerror());
             Return -1;
         }
         Printf(“"5-3=“%d\n”,p(5,3));
12         //关闭动态加载
13         dlclose(h);
14         return 0;
15 }
~

补充:
如何去掌握一个函数?
函数的功能
函数的参数,参数的类型,个数,每个参数的意义,取值
函数的返回值
Const int val = 321;
引用计数

举例

使用动态加载链接函数,动态加载动态库文件。
代码参见dynamic.c

程序中的错误处理

在C语言程序中,对错误的处理。
系统维护着一个全局变量,errno
errno是一个整数,记录的是错误的编号。
当系统调用或者库函数产生错误的时候,将errno设置相应的错误编号。程序员
可以根据错误的编号获取到错误的描述信息。
知道错误编号,如何提取出错误的描述信息。

perror(3).  

Void terror(const char *s);

功能:输出一条系统的错误消息

参数:
S:程序员指定的字符串
返回值:void
FILE *fp
标准错误输出:
标准输入: 键盘 stdin
标准输出: 显示器 stdout
标准错误输出: 显示器 stderr

流式文件 文件流

#include<stdio.h>
Char *strerror(int errnum)

功能:获取errnuo对应的描述信息。
参数
errnum:错误编号
返回值:
返回errnum对应的错误信息
如果错误号没有定义,返回“unknown error nnn”

举例:

只读方式打开一个文件,文件不存在。报错

  1 #include<stdio.h>
  2 #include<errno.h>
  3 extern int errno;
  4 int main(void){
  5         FILE *fp;
  6         fp= fopen("helloda","r");
  7         if(fp == NULL){
  8                 printf("errno:%d\n",errno); //打印错误号
  9                 return -1;
10         }
11         printf("file open success ... \n");
12         fclose(fp);
13         return 0;
14 }
~```
~


## 内存管理

虚拟地址             物理地址   

页标。 页。 页框

映射的基本单位是4k。叫做页

段错误产生的原因。用户访问的虚拟地址没有实际的无力地址对应。



`swap` 交换分区。  虚拟内存
程序运行在操作系统上,取到的地址就是虚拟地址。
没有操作系统的时候可以直接使用物理地址。
每个进程都可以访问4G的虚拟地址空间。

寄存器。   容量小。速度极快
`Cache`.      少。        速度快。cpu内部器件



内存        容量大            速度一般
 硬盘           容量很大           速度慢
 net            容量极大            速度极慢

冯。诺伊曼。体系结构
哈佛体系结构

区域    代码区       数据区        栈区
A.0        b.o            a.out    
代码区    代码区        代码段
数据区    数据区        数据段

堆栈                堆是堆        栈是栈


代码段            数据段            栈段        堆

每一个段的属性,哪些变量的空间分配在哪个段里?

每个进程都有自己的身份证。进程的身份证是pid

如何获取进程的pid?

getpid(2)

include<sys/types.h>

include<unistd.h>

Pid_t getpid(void);

   **功能**:获取进程的id
**参数**:
void

**返回值**:
函数永远成功,返回当前进程的pid

`pid_t. Int`


## 举例。   进程的内存布局

`Cat /proc/pid/maps`.  可以看到进程的虚拟地址空间的布局

总结:

一,动态加载
二,错误处理
三,内存管理
Responses