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

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

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

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);
}
23、深入理解静态库共享库:原理、应用与对比 本文深入探讨了静态库共享库的原理、应用与对比,涵盖了共享库的搜索配置、位置无关代码的编译、共享内容的控制以及动态加载的具体实现方法。通过对比静态库共享库的优缺点,分析了它们在不同场景下的适用性。此外,文章还介绍了动态库加载的流程、性能优化策略、安全性考虑以及错误处理机制,帮助开发者在实际开发中更好地选择使用库,提高开发效率系统性能。 阅读详情

相关推荐

解决共享库不存在或失效导致的应用未安装

找了很久,,资源都是分开的 这次我把他汇总,打包,方便下载了 不用一个一个的找了下了 很多使用安卓的朋友应该都遇到过安装某些软件出现”应用未安装“,用电脑手机助手进行安装时会出现没有该软件的共享库或已失效,这个问题大概困扰了我3天时间,终于在我的坚持下找到了解决方法,希望出现过这样问题的朋友严格安装我下面的步骤操作即可解决以上问题! 第一步:使用第三方工具中的ROOT获取工具,进行获取ROOT权限。 第二步:下载ROOT EXPLORER 具有最高权限的文件管理工具,安装并打开(打开时出现是否允许此软件使用最高权限,允许)。 第三步:下载以下三个文件。 com.google.android.maps.jar com.google.android.maps.xml NetworkLocation.apk 第四步:使用ROOT EXPLORER 文件工具将三个文件以下面的说明操作。 com.google.android.maps.jar 拷贝到根目录的 system/framework/ 文件夹下面。 然后将此文件的权限设为 root 权限,然后在设置访问权限对话框上选项上对话框选项有9个可打钩的方格,把左边三个的全部勾选,中间的三个的第一个勾上即可。 com.google.android.maps.xml 拷贝到根目录的 system/etc/permissions/ 文件夹下面。 同上面的设置权限的方法一样。 NetworkLocation.apk 拷贝到根目录的 data/app_s/ 文件夹下面。 (如果找不到 app_s这个文件夹,可以新建一个 app_s文件夹,然后在将其拷贝进去)!将此文件的权限设置为 system 然后在设置访问权限对话框上选项上对话框选项有9个可打钩的方格,将左边三个全部勾上,中间的第一个第二个勾上,右边全部勾上即可。然后重启手机,开始安装你以前安装失败的软件,然后你就会看到安装成功的兴奋了。这样你就永远不会在遇到软件未安装或没有该软件的共享库或已失效的情况了。

使用GPL的动态库,未修改源码,是否必须GPL开源?(***)

使用GPL的动态库,未修改源码,是否必须GPL开源?

ken2232的博客 3259

静态库动态库里的全局变量(或类的静态成员变量)共享独立的问题

测试代码说明以下两个问题: 1. 工程中包含静态库A,动态库B,可执行程序C。C依赖于AB,而B依赖于A。在A中定义有全局变量X(或类的静态成员变量),则在动态库B中访问的X,与可执行程序C中访问的X是同一个变量还是两个不同的变量? 答案:是两个不同的变量。 2. 工程中包含动态库A,动态库B,可执行程序C。C依赖于AB,而B依赖于A。在A中定义有全局变量X(或类的静态成员变量),则在动态库B中访问的X,与可执行程序C中访问的X是同一个变量还是两个不同的变量?(注:所有库都在同一进程中使用) 答案:是共享同一个变量。即:在A是动态库的这种情况下,BC访问到的X是同一变量。 博文地址:http://blog.csdn.net/guggy/article/details/8136325 或即时记:http://www.livelog.cn/bbs/viewthread.php?tid=16

GPLV2协议重点F&Q整理与总结

针对GPL软件二次开发人员的重点GPL F&Q整理总结。

gao1738的专栏 4531

GPL(GNU通用公共许可证)对动态库共享库)的影响

动态链接GPL库可能触发传染性,除非适用例外(如系统库或LGPL)。LGPL是更灵活的选择,而GPL的动态链接需谨慎对待以避免合规风险。

weixin_42849849的博客 919

Linux系统编程 31 动态库加载错误原因及解决方式2

Linux系统编程 31 动态库加载错误原因及解决方式2 标准库的时候,就没有修改LD_LIBRARY_PATH, 就可以直接使用。-》动态链接器会去标准c库中 去找想要的动态库。 1.所以我们可以把我们建立的动态库放在标准c库的位置 cp libmymath.so /lib cp: cannot create regular file ‘/lib/libmymath.so’: Permission denied $sudo cp libmymath.so /lib [sudo] passwor..

sinat_36070482的博客 1393

动态库共享库静态库

gcc -c  a.c : 编译成目标文件 gcc -o  a.c : 生成可执行文件 gcc a.c :生成执行文件a.exe 总结:只要参数有-c,总是生成目标文件;只要参数中无-c而只有-o, 则总是生成执行文件。 通常库分为:静态库共享库动态加载库。 一、静态库—— 一些目标文件的集合。以.a结尾。 1. 使用场合:程序链接时使用。链接器会将程序中使用到得函数代码从

wjf201003050643的博客 142

动态库(共享库)静态库的制作与使用

库文件 ​ 把源文件编译成二进制的目标文件后,合并打包在一起形成的目标文件的集合叫库文件。 静态库 ​ 使用静态库时,是把静态库文件的被调用代码复制到调用模块中 ​ 1、使用静态库生成出的可执行程序速度快 ​ 2、使用静态库生成的可执行程序相对较大 ​ 3、当静态库发生变化时,调用者需要重新编译,维护升级麻烦 ​ 4、扩展名.a 动态库动态库也叫共享库,使用动态库时,是把动态库文件的被调用代码的位置记录到调用模型中,生成一个跳转指令 ​ 1、生成的可执行程序与静态库相比速度慢,而且需要

weixin_51420051的博客 279

动态库静态库在编译C语言时使用方法简述

函数库分为静态库动态库两种。创建Linux静态库Linux动态库使用它们在这里将以举例的形式详述一下。静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。   第1步:编辑得到举例的程序——hello.h、hello.cmain.c;   hello.h(

君子不器 2180

头文件与库文件、静态链接与动态链接、静态库动态库共享库

1、头文件在哪里? 头文件:作为一种包含功能函数、数据接口声明的载体文件,主要用于保存函数的声明。C++标准库头文件,不同的编译器默认路径不相同。 Vc6.0:一般在安装目录下的\VC98\INCLUDE目录, 比如C:\Program Files (x86)\Microsoft Visual Studio\VC98\INCLUDE。 Vs:一般在位于$VSPATH\VC\include...

qq_39191122的博客 3490

qt调用c语言函数库_QT 加载c语言编译的动态库

QLibrary lib("./libprint.so");//库的路径if(lib.load()){typedef void(*AddFunction)(char *str[]);//typedef void(__attribute((__cdecl__)) *AddFunction)(char *str[]);这种方法也可以//对于__attribute__ 的有关内容参考http://b...

weixin_39786850的博客 858

C语言的动态库静态库的制作与使用

文件,把库所在的路径加到文件末尾,执行。当终端关闭后,这个环境变量自动销毁。环境变量中加上库所在的路径。原因:默认执行的是在。拷贝或者移动到对应的。

Dreamer2176的博客 335

编程的奥妙——静态库动态库的建立与运用

一、GNU编译器 1、支持众多编程语言、平台 2、构建过程(C代码是如何变成可执行文件的)。 预处理:把程序员所编译的C代码翻译成标准的C代码 汇编:把预处理后的C代码翻译成汇编代码 编译:把汇编代码翻译成二进制指令 链接:把若干个目标文件合并成一个可执行文件 3、gcc -v 查看版本 4、文件后缀 .h 头文件 .gch 头文件的编译结果,一般不要保留。 .c 源文件 .i 预处理文件 .s ...

qq_44126789的博客 215

Linux-Level2-day02:静态与动态库详解;动态加载动态库方法;程序信息辅助工具;错误号错误信息;环境变量读写操作;

23点53分

dpq666dpq666 321

linux 静态库动态库简单使用示例

nm 命令可以看二进制文件的符号 预编译 去掉宏 gcc -E hello.c -o hello.i 编译 高级语言-->汇编 gcc -S hello.i 汇编 汇编-->目标文件 gcc -c hello.s 链接 gcc hello.o -o hello .h 源码头文件 .c 预处理前的源码 .i 预处理后的源码 .s 汇编语言文件 .o 目标文件 .a 静态库 .s...

wWX336815的博客 339

linux下的静态库动态库的编译

转自:http://www.diybl.com/course/6_system/linux/Linuxjs/20071027/80547.html 每个程序实质上都会链接到一个或者多个的库。比如使用C函数的程序会链接到C运行时库,GUI程序会链接到窗口库等等。无论哪种情况,你都会要决定是链接到静态库(static libary)还是动态库(dynamic libary)。 链接到静态库会使

godcyx的专栏 605

UNIX系统Linux系统介绍,GNU编译工具的使用,静态库动态库的制作使用以及优缺点

系统环境:库、环境变量、编译器、系统特性内存管理:操作系统是如何管理内存的文件系统:文件读写、目录读写、文件属性、文件管理进程管理:多个程序同时运行,解决复杂问题信号处理:操作系统与程序之间一种通信机制进程通信:多个进程如何交互数据,这是它们协同工作的基础线程管理:就是让一个程序同时做若干件事情线程同步:让多个线程同时工作时能够不互相破坏、干扰。

Hidin的博客 367

c动态库静态库

在商业开发中,提供的代码 不是 .c,也不是.o文件,而是把 .o文件打包成 库文件。程序员只需要提供 头文件库文件。   Unix/Linux的库文件分为两类:    静态库    共享库(动态库)    静态库 就是把.o文件做了一个归档,在调用函数时,把整个函数的代码段直接复制到可执行文件中。    共享库 就是把.o文件做了一个归档,在调用函数时,把函数在库中的地址复制到可执行

226
上一篇: gcc编译过程 常用指令:#warning/#error/#pragma 环境变量 头文件
下一篇: 环境表 内存管理-malloc()/free()
Robot__Man
博客等级 码龄12年 251粉丝 109原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值