回顾:
Linux/Unix的简介
gcc的用法
预处理的指令 #error #warning #pragma
环境变量
PATH/CPATH/....
头文件 - 自定义头文件
今天:
静态库和共享库(动态库)
C语言的错误处理
环境变量在程序中的处理(环境表)
内存管理
由于项目比较复杂,代码数量非常庞大,可以把代码打包成库文件,提供库文件和头文件即可。
库文件分为两种:
静态库 和 共享库(动态库),静态库和共享库都是代码的归档文件。使用静态库时,把静态库的代码 复制到 目标文件中,导致目标文件比较大;使用共享库时,把函数的地址 放到目标文件中。
静态库和共享库的优缺点:
静态库的优点:目标文件独立于库文件,运行速度稍快。缺点:目标文件比较大,不利于代码的修改、扩展和复用。
共享库的优点:目标文件比较小,修改、扩展和复用代码比较方便。缺点:目标文件必须和共享库文件同时存在,代码才能正常运行。运行速度稍慢。
开发多半使用 共享库。
使用静态库的步骤:
创建静态库(.a)
1 写源程序 add.c 保存退出
2 编译源程序,得到 .o 文件(gcc -c)
3 创建静态库文件:
ar -r libXX.a add.o
注:lib开头 .a结束是静态库的命名规范。XX是库名
创建静态库文件后,还需要提供 .h文件。
使用静态库
1 写调用源程序 test.c,保存退出
2 编译test.c,只编译不连接(gcc -c)
3 连接 test.o 和静态库文件。
连接方式有三种:
a 直接连接
gcc test.o libXX.a
b 配置环境变量LIBRARY_PATH,把库文件所在路径放入其中,然后:
gcc test.o -lXX
c gcc test.o -lXX -L所在路径 (双L,推荐)
使用共享库的步骤:
创建共享库
1 写源程序add.c,保存退出
2 编译
gcc -c -fpic add.c (不写-fpic也行)
3 生成共享库
gcc -shared add.o -olibXX.so
注:共享库也需要提供头文件
使用共享库
和静态库方式一样。
注:连接成功后,需要配置LD_LIBRARY_PATH才能运行成功。
ldd 命令可以查看 使用的共享库。
动态调用共享库(动态编程)
代码在运行时才知道调用哪个函数,执行哪段代码
相关函数:
dlopen() dlsym() dlclose()
错误处理 dlerror()
dlopen:打开共享库文件
dlclose: 关闭共享库文件
dlsym: 从一个打开的库文件中获得一个函数,返回函数指针。
man 查看帮助手册,英文翻译软件:星际译王
dlopen()第一个参数是 共享库的文件名,第二个参数是加载方式:
RTLD_LAZY - 延迟加载,open时不加载,使用时加载
RTLD_NOW - open文件的同时加载
返回 库文件的首地址。
错误处理
C程序没有异常,因此错误处理有自己的一套机制:
用返回值的不同体现错误。
1 返回指针类型,一般用NULL代表错误。
2 返回int类型,返回数据不可能是-1,一般用-1代表错误。
3 返回int类型,但返回数据有可能是-1,用指针取回数据,用返回 -1 代表错误,返回0 代表正确。
4 如果不需要考虑错误处理,返回值为void。
以上4种情况都是一般用法(惯例),都有特殊情况。
练习:
有4个函数,实现代码和错误处理
a 打印传入的字符串 4
b 测试传入字符串的值,如果不是error,返回ok,如果是error,代表出错,处理的函数错误。 1
c 返回0-10的随机数,如果随机到5,代表出错 2
d 求两个整数的最大值,如果相等,代表出错。3
C对于错误处理提供了一个外部全局变量,三个函数:
errno - 错误的编号,不包括错误信息
strerror() - 把错误编号 转换成 错误信息
perror() -自动找到错误编号并打印对应的错误信息
printf() -"%m"自动打印错误信息
最常用的错误处理函数就是 perror().
perror()允许传入一些附加信息,帮助程序员定位哪里出了错误。
errno 是一个全局变量,可以直接使用。使用方式:成功不改变值,失败设置值。不是所有的函数都使用errno处理错误。
环境变量和环境表
所有的环境变量在程序中可以通过环境表获取。
环境表是一个全局变量,类型 字符指针数组,以NULL结束,获取方式:
extern char** environ;
environ就是环境表的首地址,是全局变量
作业:
写2个函数,打印实心菱形和空心菱形,分别存成静态库和共享库,写调用代码并成功调用。
空心菱形代码选作。