您的位置:首页 > 其它

静态库和共享库(动态库) 动态调用共享库 C的错误处理

2016-06-12 19:30 309 查看

一 静态库和共享库(动态库)

1 静态库和共享库简介

  由于项目比较复杂,代码数量非常庞大,可以把代码打包成库文件,提供库文件和头文件即可。

  库文件分为两种:

  静态库和共享库(动态库),静态库和共享库都是代码的归档文件。使用静态库时,把静态库的代码复制到目标文件中,导致目标文件比较大;使用共享库时,把函数的地址放到目标文件中。

  静态库和共享库的优缺点:

  静态库的优点:目标文件独立于库文件,运行速度稍快。缺点:目标文件比较大,不利于代码的修改、扩展和复用。

  共享库的优点:目标文件比较小,修改、扩展和复用代码比较方便。缺点:目标文件必须和共享库文件同时存在,代码才能正常运行。运行速度稍慢。

  开发多半使用 共享库。

2 静态库的使用

使用静态库的步骤:

2.1 创建静态库(.a)

1 写源程序 add.c 保存退出

2 编译源程序,得到 .o 文件(gcc -c)

3 创建静态库文件:

  ar -r libXX.a add.o

注:lib开头 .a结束是静态库的命名规范。XX是库名

创建静态库文件后,还需要提供 .h文件。

2.2 使用静态库

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,推荐)

add.h
#ifndef ADD_H_
#define ADD_H_
int add(int,int);
double add2(double,double);
#endif


add.c
int add(int a,int b){
return a+b;
}
double add2(double a,double b){
return a+b;
}


test.c
#include <stdio.h>
#include "add.h"
//#include <add.h>

int main(){
int r = add(2,3);
double d = add2(1.0,4.0);
printf("r=%d,d=%lf\n",r,d);
}


3 共享库的使用

使用共享库的步骤:

3.1 创建共享库

1 写源程序add.c,保存退出

2 编译

  gcc -c -fpic add.c (不写-fpic也行)

3 生成共享库

   gcc -shared add.o -olibXX.so

注:共享库也需要提供头文件

gcc -fpic -shared add.c -o libadd.so,这一条命令生成库也行

3.2 使用共享库

和静态库方式一样。

注:连接成功后,需要配置LD_LIBRARY_PATH才能运行成功。

ldd 命令可以查看 使用的共享库。

二 动态调用共享库(动态编程)

代码在运行时才知道调用哪个函数,执行哪段代码

相关函数:

  dlopen() dlsym() dlclose()

  错误处理 dlerror()

dlopen:打开共享库文件

dlclose: 关闭共享库文件

dlsym: 从一个打开的库文件中获得一个函数,返回函数指针

dlopen()第一个参数是 共享库的文件名,第二个参数是加载方式:

  RTLD_LAZY - 延迟加载,open时不加载,使用时加载

   RTLD_NOW - open文件的同时加载

 返回 库文件的首地址。

man 查看帮助手册,Linux下英文翻译软件:星际译王

dl.c
#include <stdio.h>
#include <dlfcn.h>

int main(){
void* handle = dlopen("./libmyku.so",
RTLD_NOW);
char* error = dlerror();
if(error/*!=NULL*/){//!=NULL可以省略
printf("open error\n");
return -1;
}
double (*f)(double,double);//换一下函数名
f = dlsym(handle,"add2");
double d = f(2.0,4.0);
printf("d=%lf\n",d);
dlclose(handle);
}//gcc dl.c -ldl


三 C的错误处理

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

err.c
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
void print(char* str){
printf("%s\n",str);//\n换行,不会不打印
}

char* iferror(char* str){
if(strcmp(str,"error")==0){
return NULL;//“NULL” NULL不同
}//前者是具体字符串 NULL才是空
return "OK";
}

int getrand(){
srand(time(0));
int r = rand()%11;
if(r == 5) return -1;
/*else*/ return r;
}

int max(int a,int b,int *pi){
if(a == b)
return -1;
*pi = (a>b)?a:b;
}

int main(){
print("hello");
char* s = iferror("eror");
if(s == NULL){
printf("出错了\n");
return -1;
}
printf("%s\n",s);
int r = getrand();
if(r == -1) {
printf("rand出错了\n");
return -1;
}
printf("r=%d\n",r);
int maxi;
r = max(2,2,&maxi);
if(r == -1) {
printf("max出错了\n");
printf("errno=%d\n",errno);
return -1;
}
printf("max=%d\n",maxi);
}


C对于错误处理提供了一个外部全局变量,三个函数:

errno - 错误的编号,不包括错误信息

strerror() - 把错误编号 转换成 错误信息

perror() -自动找到错误编号并打印对应的错误信息

printf() -“%m”自动打印错误信息

最常用的错误处理函数就是 perror()。

perror()允许传入一些附加信息,帮助程序员定位哪里出了错误。

  errno 是一个全局变量,可以直接使用。使用方式:成功不改变值,失败设置值。不是所有的函数都使用errno处理错误。

perror.c
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(){
FILE* file=fopen("/etc/passwd1","r");
printf("errno=%d\n",errno);
if(file == NULL){
//printf("open:%s\n",strerror(errno));
//printf("oepn: %m\n");
perror("open passwd1");
//return -1;
}
else {
printf("open ok\n");
}
file = fopen("/etc/passwd","r");
printf("errno=%d\n",errno);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: