• windows和ubuntu下显式调用dll库文件的异同


    windows和ubuntu下显式调用dll库文件的异同

    除了将dll库文件作为一部分参与主程序编译之外,显式的调用库文件也是一种灵活的使用方式。
    调用dll库文件依赖于系统,所以不同的系统下是不同的。
    像c++这种静态编译程序就要注意这样的不同,而python这种动态程序由于解释器已经做了处理则可以忽略系统的差异。本文就讨论一下这些内容:

    1. c++程序显式调用库文件

    c++程序显式的调用库文件,就是在程序中显式的打开库文件,并定位和使用其中的函数。

    1.1 windows下的调用

    下面的c++源程序是典型的windows系统下dll显式调用程序:

    #include 
    #include 
    
    #include 
    using namespace std;  
    
    typedef double (*WinrateFunc)(int, int,int,int, int, int, int, int, int);
    typedef void (*Wrlibinit)();
    
    
    /* main.cpp */  
    int main(){
    		
    	//动态加载Dlltest.dll文件
    	HINSTANCE hDll;
    	hDll= LoadLibrary(TEXT("libwinrate.so"));
    	
    	//测试是否能够正确输出
    	//printf("%s\n","absededeedd");
    	//cout<<"absededeedd"<
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    其中:

    (1)#include 是调用dll的系统头文件依赖;

    (2)hDll= LoadLibrary(TEXT("libwinrate.so"));则是显式的打开库文件;

    (3)typedef void (*Wrlibinit)(); 则是声明库文件中函数及其参数的类型;

    (4)Wrlibinit getwrinit = (Wrlibinit)GetProcAddress(hDll, "compinit");则是定位获取库文件中的函数;

    (5)getwrinit();则是使用库文件中的函数。

    (6)FreeLibrary(hDll);则是使用完dll后显式的关闭库文件。

    1.2 ubuntu下的调用

    linux系统如ubuntu下由于依赖的系统库的不同,所以有所差别,其典型程序如下:

    #include 
    #include 
    //windows
    //#include 
    //linux
    #include 
    
    
    using namespace std;  
    
    typedef double (*WinrateFunc)(int, int,int,int, int, int, int, int, int);
    typedef void (*Wrlibinit)();
    
    
    /* main.cpp */  
    int main(){
    		
    	//动态加载Dlltest.dll文件
    	void* hDll;
    	hDll= dlopen("./libwinrate.so",RTLD_LAZY);
    	
    	if (hDll != NULL)
        {
    		
    		printf("%s\n","dll loaded!!");
    
    		WinrateFunc getwinrate = (WinrateFunc)dlsym(hDll, "get_winrate");
    		Wrlibinit getwrinit = (Wrlibinit)dlsym(hDll, "compinit");
    		if (getwinrate != NULL) {
    			getwrinit();
    			double wr=getwinrate(2,5,24,37,15,18,45,51,34);
    			cout<<"wr="<
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    其中:

    (1)#include 是调用dll的系统头文件依赖;

    (2)hDll= dlopen("./libwinrate.so",RTLD_LAZY);则是显式的打开库文件;

    (3)typedef void (*Wrlibinit)(); 则是声明库文件中函数及其参数的类型;

    (4)Wrlibinit getwrinit = (Wrlibinit)dlsym(hDll, "compinit");则是定位获取库文件中的函数;

    (5)getwrinit();则是使用库文件中的函数。

    (6)dlclose(hDll);则是使用完dll后显式的关闭库文件。

    1.3 两个系统下的比较

    两个系统下dll调用的差异,如下表所示:

    差异项windowsubuntu
    头文件依赖windows.hdlfcn.h
    库打开LoadLibrarydlopen
    函数获取GetProcAddressdlsym
    库关闭FreeLibrarydlclose
    ------------
    相同项windowsubuntu
    函数类型声明使用typedef定义同左
    库中函数使用直接使用获取的函数同左
    ------------

    2. python程序显式调用库文件

    而python由于其解释器本身就是跨平台的所以在不同的系统下,其函数的调用是相同的,而且接口更为简单。
    其典型程序如下:

    #!/usr/bin/env python3
    #_*_coding: utf-8 _*_
    
    import sys
    import json
    import struct
    import socket
    
    from ctypes import *  #用import *的方式可以把c_float,c_double等类型载入进来,而不用再带一个ctypes.
    loadlib = cdll.LoadLibrary
    
    lib = loadlib("./libwinrate.so")
    lib.compinit()
    getwinrate=lib.get_winrate
    getwinrate.argtypes = [c_int,c_int,c_int,c_int,c_int,c_int,c_int,c_int,c_int]
    getwinrate.restype= c_double
    
    wr=getwinrate(2,5,24,37,15,18,45,51,34)
    print("wr=",wr,' true val=',0.2631313131313131)
    
    wr=getwinrate(2,0,10,52,0,0,0,0,0)
    print("wr=",wr,' true val=',0.5672969999999999)
    
    wr=getwinrate(2,4,21,39,29,17,26,1,0)
    print("wr=",wr,' true val=',0.40303030303030307)
    
    wr=getwinrate(3,0,29,35,0,0,0,0,0)
    print("wr=",wr,' true val=',0.3575082176846212)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    其中:

    (1)lib = loadlib("./libwinrate.so") 是调用dll;

    (2) 库中的函数可以直接使用,比如lib.compinit()

    (3) 库中的函数可以赋给一个对象后使用,比如getwinrate=lib.get_winrate

    (4) 最好声明一下函数的输入输出类型,比如getwinrate.argtypesgetwinrate.restype

    3. 库文件编译的差异

    对于自己用c++编写的库文件,也是需要在不同的系统下编译的,因此对于程序本身可能依赖的部分头文件差异外最大差异是编译命令的差异:

    windows 典型为:

    g++ -g -std=c++11  -shared -Wall -o libwinrate.so winrate.cpp pokerlib.cpp  mtrand.cpp  -O3
    
    • 1

    ubuntu下典型为:

    g++ -g -std=c++11  -shared -fPIC -o libwinrate.so winrate.cpp pokerlib.cpp  mtrand.cpp  -O3  -fno-stack-protector
    
    • 1

    4. 小结

    本文简单介绍了不同系统下程序显式调用dll库文件的差异,为不同系统下的程序迁移提供帮助。

    参考:

    1. 【qt/c++调用dll的方法实践】
  • 相关阅读:
    php fpdf使用记录
    JavaWeb-Session和Cookie
    Vue中引入jQuery两种方式可在vue中引入jQuery
    Effective Modern C++[实践]->只要函数不会发射异常,就为其加上noexcept
    使用C++编写STM32软件IIC
    Cmasher颜色包--共53种--全平台可用
    Apache DolphinScheduler - 快速扩展 TaskPlugin 从入门到放弃
    用57000字讲解完2022年Java岗面试最常问的100道题,太肝了
    PyQt5快速开发与实战 10.1 获取城市天气预报
    思维导图解读《思考,快与慢》
  • 原文地址:https://blog.csdn.net/xenonhu/article/details/126452663