相关文章推荐
重情义的红豆  ·  git push后出现src ...·  1 年前    · 
稳重的钥匙  ·  《Android ...·  2 年前    · 
无聊的莴苣  ·  如何删除SQL ...·  2 年前    · 

C语言动态链接库的搭建和使用

1 个月前

1. 概述

在c语言的实际编程中,我们可以把完成某项功能的函数放在一个动态链接库里,然后提供给其他程序调用。

1.1 动态库

动态库是一种不可执行的二进制程序文件,它允许程序共享执行特殊任务所必需的代码和其他资源。Windows平台上动态链接库的后缀名是”.dll”,Linux平台上的后缀名是“.so”。Linux上动态库一般是libxxx.so;相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。

1.2 动态链接库的优点

复用性:DLL的编制与具体的编程语言以及编译器无关,不同语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数

可扩展性:DLL文件与EXE文件独立,只要接口不变,升级程序只需更新DLL文件不需要重新编译应用程序

节省内存:如果多个应用程序使用同一个dll,该dll的页面只需要存入内存一次,所有的应用程序都可以共享它的页面,从而节省内存

2. 生成动态链接库

仅对windows系统进行描述,下面以vs编译器为例:

在创建新项目中选择“动态链接库”

项目的命名就是最后dll的名字,新建h和cpp文件

main.cpp

#include "main.h"

#include <stdio.h>

/* 输入年月日计算一年中第几天 */

int Day_of_year(int year, int month, int day)

{

int sum,leap;

switch(month) // 先计算某月以前月份的总天数

{

case 1:sum=0;break;

case 2:sum=31;break;

case 3:sum=59;break;

case 4:sum=90;break;

case 5:sum=120;break;

case 6:sum=151;break;

case 7:sum=181;break;

case 8:sum=212;break;

case 9:sum=243;break;

case 10:sum=273;break;

case 11:sum=304;break;

case 12:sum=334;break;

default:printf("data error");break;

}

sum=sum+day; // 再加上某天的天数

if(year%400==0||(year%4==0&&year%100!=0)) {// 判断是不是闰年

leap=1;

} else {

leap=0;

}

if(leap==1&&month>2) { // *如果是闰年且月份大于2,总天数应该加一天

sum++;

}

return sum;

}

Main.h

#ifndef __MAIN_H__

#define __MAIN_H__

#include <windows.h>

#ifdef __cplusplus

#define EXPORT extern "C" __declspec (dllexport)

#else

#define EXPORT __declspec (dllexport)

#endif // __cplusplus

EXPORT int Day_of_year(int year, int month, int day);

#endif // __MAIN_H__

编译成功后在bin\Debug目录下生成3个文件:dll.dll,libdll.a,libdll.def

3. 调用动态链接库

新建工程,把dll.dll拷贝到新工程的bin\Debug目录下

main.c

#include <stdio.h>

#include <windows.h>

typedef int(*Getday)(int, int, int); //定义函数类型

HINSTANCE hDll; //DLL句柄

Getday getday;

int main()

{

hDll = LoadLibrary("dll.dll"); //加载 dll

getday = (Getday)GetProcAddress(hDll, "Day_of_year");//通过指针获取函数方法

printf("day = %d\n", getday(2015, 10, 1) );//调用函数

FreeLibrary(hDll);//释放Dll句柄

system("pause");

return 0;

}

编译就可以使用,当dll程序升级时,只需要替换dll,而不用重新编译exe

4. 调试案例

1)错误一

/tmp/ccMpgzNu.o: In function `main':

test.c:(.text+0x13): undefined reference to `dlopen'

test.c:(.text+0x1c): undefined reference to `dlerror'

test.c:(.text+0x53): undefined reference to `dlsym'

test.c:(.text+0x63): undefined reference to `dlerror'

test.c:(.text+0x89): undefined reference to `dlclose'

test.c:(.text+0xc7): undefined reference to `dlclose'

collect2: error: ld returned 1 exit status

解决方案:

头文件添加:#include <dlfcn.h>

编译选项加上- ldl,即 gcc -o test test.c -ldl ,网上有gcc -ldl -o test test.c,这种方式也是会报这个错误的

2)错误二

error while loading shared libraries: libtiger.so: cannot open shared object file: No such file or direct

我的这段代码里则会打印Load lib.so failed!

解决方案:

在程序代码里配置路径void *pdlHandle = dlopen(“libday.so”, RTLD_LAZY);

将动态链接库配上路径,如 ./libday.so表示可执行文件与链接库同一路径

将动态链接库的目录放到程序搜索路径中,可以将库的路径加到环境变量

export LD_LIBRARY_PATH=pwd:$LD_LIBRARY_PATH(pwd带反撇号的哈)

拷贝libday.so到绝对目录 /lib

编辑于 2023-03-25 17:54 ・IP 属地辽宁