一、库:
gcc -c list_queue.c ->list_queue.o(二进制)
库文件就是目标文件的集合,库文件可以被其他代码调用,把代码封装成库文件后方便使用、方便管理、安全性高、保密性强
二、静态库:xxx.a
就是把目标文件集合成一个以.a结尾的库文件,当调用静态库时,会把静态库中使用到的二进制指令拷贝到可执行文件中
优点:运行速度比共享库快(和宏差不多),可执行文件运行时不需要依赖静态库文件
缺点:可执行文件相对比较大,如果静态库内容发生改变,所有之前使用过该静态库的可执行文件都需要重新编译
三、共享库:xxx.so
本质上就是一个带入口的可执行文件,有执行权限。当调用共享库时,在使用共享库代码的地方形成一个入口,该入口记录了调用的代码在共享库中二进制指令的位置,
并且当可执行文件时,共享库会与可执行文件一起加载到内存中,当执行共享库的代码时,程序就会跳到对应的共享库中执行,
执行完后可能会返回
优点:可执行文件相对较小,如果当共享库发生修改,可执行文件不需要重新编译,只需要重新运行即可
缺点:运行速度会比静态库稍慢、可执行文件运行时必须依赖共享4.5库
四、制作、使用静态库
制作
1、编译出目标文件
gcc -c xxx.c
2、打包目标文件生成静态库文件
arr -r libxxx.a a.o b.o……
注意:库文件格式必须是libxxx.a/libxxx.so
使用:
1、直接使用
gcc xxx.c libxxx.a
2、指定库文件的位置
-L 指定库的查找路径
-l 指定要加载的库名 -lxxx(库名去掉lib和后缀)
gcc xxx.c -L path -lname
3、通过修改环境变量来指定系统查找库文件的默认路径
1.打开系统的配置文件 vim ~/.bashrc
2.在配置文件末尾添加:export LIBRARY_PATH=$LIBRARY_PATH:/home/jtq(绝对路径)
保存退出并重新加载:source ~/.bashrc
使用静态库:gcc xxx.c -lname
注意:如果是删除配置文件中的环境变量,需要重启终端后才能生效
五、制作、使用共享库
制作:
1、编译生成目标文件
gcc -fpic -c xxx.c
-fpic:生成与位置无关的文件
2、打包生成共享库文件
gcc -fpic -shared a.o b.o…… -o libname.so
使用:
注意:共享库要一起与可执行文件加载到内存中才能运行成功,但是加载执行共享库的路径与编译使用共享库的路径是两种查找路径
因此需要额外设置共享库的加载路径,一般通过设置加载环境变量LD_LIBRARY_PATH实现
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/jtq(绝对路径)
1、直接使用
gcc xxx.c libxxx.a
2、指定库文件的位置
-L 指定库的查找路径
-l 指定要加载的库名 -lxxx(库名去掉lib和后缀)
gcc xxx.c -L path -lname
3、通过修改环境变量来指定系统查找库文件的默认路径
1.打开系统的配置文件 vim ~/.bashrc
2.在配置文件末尾添加:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/jtq(绝对路径)
保存退出并重新加载:source ~/.bashrc
使用共享库:gcc xxx.c -lname
注意:如果是删除配置文件中的环境变量,需要重启终端后才能生效
注意:当共享库和静态库同名时且在同一个查找路径下,编译器编译时会优先使用共享库进行编译,可以增加一个编译参数
-static 指定优先查找使用同名的静态库文件
六、练习:把常用的数据结构、算法封装到libdsa.so共享库中
栈、队列、通用链表、平衡二叉树
二分查找、冒泡排序、选择排序、快排、插入排序、希尔排序
七、了解
共享库的动态加载,作用是在编译时不需要依赖共享库
八、静态库、共享库相关的辅助命令
ldd 可以查看可执行文件程序依赖了哪些共享库 ldd a.out****
nm 可以查看目标文件、可执行文件、静态库、共享库中的符号列表
strip 减肥,删除目标文件、可执行文件、静态库、共享库中的符号列表
objdump 显示目标文件、可执行文件、静态库、共享库中的符号列表的反汇编信息
九、环境变量表:
每个程序执行是操作系统都会提供一张环境变量表,该表中记录了操作系统所有的环境变量这些环境变量反映了当前操作系统的
配置情况、以及当前程序所处于的系统环境。
注意:每个程序的环境变量表只是一张复制表。随便修改、不会对真正的环境变量有所影响
查看环境变量表:env
在程序中获取环境变量表:声明:extern char** environ;
操作环境变量表的相关函数:
char *getenv(const char *name)
功能:获取表中某一个环境变量的值
name:环境变量名
返回值:返回环境变量的值
int setenv(const char* name,const char *value,int overwrite);
功能:对环境变量表中的环境变量进行增加或修改
name:环境变量名
value:环境变量的值
overwrite:当环境变量存在时 为真则会修改环境变量 为假则不会修改
返回值:0表示修改成功;-1表示失败
int putenv(char* string)
功能:以"name=value"格式增加或修改某个环境变量,如果存在则修改,不存在则新增
返回值:0表示成功,-1表示失败
int unsetenv(const char* name);*
功能:删除某个环境变量
返回值:0表示成功,-1表示失败
int clearenv(void)
功能:清空整张环境变量表
练习1:
1、添加环境变量 ZHIZHEN_PATH=/home/jtq
2、删除LD_LIBRARY_PATH
3、给ZHIZHEN_PATH追加一个路径ZHIZHEN_PATH=/home/jtq:
错误处理:
1、通过函数的返回值表示错误:
1.合法值表示成功,非法制表示失败,例如计算大小,长度,查找下标
2.返回值是指针类型
返回NULL/0xFFFFFFFF 表示失败,其余都成功
3.返回0表示成功。返回-1表示失败,一般都是系统函数
4.永远成功 printf
2、通过影响一个全局的错误编号变量 errno,声明在errno.h中
char *strerror(int errnum);
功能:返回错误编号对应的错误信息
注意:errno是一个全局变量,很容易被其他人修改,不能根据他的值判断是否产生错误
void perror(const char *s)
s:自行添加的提示信息,一般放可能出错的函数名
练习2:实现一个函数,计算文件的大小
练习3:实现一个字符串子串查找函数,功能参考strstr
练习4:实现一个求两个数平均值的函数 int
Linux的内存管理:
一、内存管理的调用层
用户层:
STL:C++的标准语法库,自动申请,自动释放 底层调用C++
C++:new/delete 底层调用C语言
C: malloc/free 调用POSIX或者Linux
POSIX: brk/sbrk 调用内核kernal
Linux: mmap/munmap 调用内核kernal
系统层:
kernal kmalloc/vmalloc 调用驱动
driver get_free_page
二、进程映像
程序是存储在磁盘上的可执行文件(二进制文件、脚本文件)
当执行程序时,系统会自动将该文件加载到内存中,在内存的分布情况称为进程映像
从低地址到高地址的分区:
text 代码段
data 数据段
bss 静态数据段
heap 堆
stack栈
environ 环境变量表
argv 命令行参数
命令:ps -aux 查看当前所有进程信息
可以查看进程号
作业:打印出每个内存段中的数据所在的地址,然后与进程的内存信息记录文件中的地址对比
/proc/进程号/maps