C調用C++的動態庫


https://zhuanlan.zhihu.com/p/270265066

https://doc.qt.io/qt-5/qtserialbus-socketcan-overview.html

https://www.coder.work/article/174502

http://www.qtcn.org/bbs/simple/?t24903.html

https://bbs.csdn.net/topics/391930574

https://qtguide.ustclug.org/ch07-02.htm

https://www.jianshu.com/p/317cf4a98c77

https://www.jianshu.com/p/15e681a0fdcb

https://developer.aliyun.com/article/114654

http://www.emtronix.com/article/zhishi2014426.html

https://www.codenong.com/js15e681a0fdcb/

 

轉載鏈接:https://blog.csdn.net/chenjinlong126/article/details/78990350

https://m.xp.cn/b.php/79361.html

https://my.oschina.net/u/4228078/blog/3119351

 推測除了so動態庫的方式,應該還有另外一種方式,即g++和gcc分別編譯C++和c文件,生成目標文件o,最后鏈接到一起。

C++調用C語言編譯的so文件

一.制作so文件:libadd_c.so或libadd_cpp.so

1、add.c:

int add(int a, int b)
{
    return a + b;
}

 

編譯:

gcc -shared -fpic -lm -ldl -o libadd_c.so add.c

2、add.cpp:

復制代碼
extern "C" {

    int add(int a, int b)
    {
        return a + b;
    }

}
復制代碼

編譯:

gcc -shared -fpic -lm -ldl -o libadd_cpp.so add.cpp

 

2.編寫測試函數

test.cpp:

復制代碼
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int main()
{
    int a = 0;
    void *handle = dlopen("./libadd_c.so", RTLD_LAZY);
    if(!handle)
    {
        printf("open lib error\n");
        cout<<dlerror()<<endl;
        return -1;
    }
    typedef int (*add_t)(int a, int b);
    add_t add = (add_t) dlsym(handle, "add");
    if(!add)
    {
        cout<<dlerror()<<endl;
        dlclose(handle);
        return -1;
    }
    a = add(3, 4);
    printf("a = %d\n",a);
    dlclose(handle);
    return 0;
}
復制代碼

編譯:

g++ test.cpp -ldl -o test

 

 3.運行

./test

 參考:

介紹一下上面用到的接口函數

1) dlopen

函數原型:void *dlopen(const char *libname,int flag);

功能描述:dlopen必須在dlerror,dlsym和dlclose之前調用,表示要將庫裝載到內存,准備使用。如果要裝載的庫依賴於其它庫,必須首先裝載依賴庫。如果dlopen操作失敗,返回NULL值;如果庫已經被裝載過,則dlopen會返回同樣的句柄。

參數中的libname一般是庫的全路徑,這樣dlopen會直接裝載該文件;如果只是指定了庫名稱,在dlopen會按照下面的機制去搜尋:

a.根據環境變量LD_LIBRARY_PATH查找

b.根據/etc/ld.so.cache查找

c.查找依次在/lib和/usr/lib目錄查找。

flag參數表示處理未定義函數的方式,可以使用RTLD_LAZY或RTLD_NOW。RTLD_LAZY表示暫時不去處理未定義函數,先把庫裝載到內存,等用到沒定義的函數再說;RTLD_NOW表示馬上檢查是否存在未定義的函數,若存在,則dlopen以失敗告終。

2) dlerror

函數原型:char *dlerror(void);

功能描述:dlerror可以獲得最近一次dlopen,dlsym或dlclose操作的錯誤信息,返回NULL表示無錯誤。dlerror在返回錯誤信息的同時,也會清除錯誤信息。

3) dlsym

函數原型:void *dlsym(void *handle,const char *symbol);

功能描述:在dlopen之后,庫被裝載到內存。dlsym可以獲得指定函數(symbol)在內存中的位置(指針)。如果找不到指定函數,則dlsym會返回NULL值。但判斷函數是否存在最好的方法是使用dlerror函數,

4) dlclose

函數原型:int dlclose(void *);

功能描述:將已經裝載的庫句柄減一,如果句柄減至零,則該庫會被卸載。如果存在析構函數,則在dlclose之后,析構函數會被調用。

好了,現在來編譯打包,命令如下:

$ g++ -shared -fPIC -o libhello.so hello.cpp
$ g++ main.cpp -ldl

在上面dlopen函數中,看到我們傳的第一個參數並沒有指定路徑,只給出了庫的名稱。那是因為已經在環境變量LD_LIBRARY_PATH中指定了 ./ 目錄。如果你想放在其他目錄,修改該環境變量即可。

 

在C語言中調用C++做的動態鏈接庫
今天在做東西的時候遇到一個問題,就是如何在C語言中調用C++做的動態鏈接庫so文件
如果你有一個c++做的動態鏈接庫.so文件,而你只有一些相關類的聲明, 那么你如何用c調用呢,別着急,本文通過一個小小的例子,讓你能夠很爽的搞定.
鏈接庫頭文件:
head.h

class A
{
public:
A();
virtual ~A();
int gt();
int pt();
private:
int s;
};

firstso.cpp

#include <iostream>
#include "head.h"

A::A(){}
A::~A(){}
int A::gt()
{
s=10;
}
int A::pt()
{
std::cout<<s<<std::endl;
}

編譯命令如下:
g++ -shared -o libmy.so firstso.cpp
這時候生成libmy.so文件,將其拷貝到系統庫里面:/usr/lib/
進行二次封裝:

secso.cpp

#include <iostream>
#include "head.h"
extern "C"
{
int f();
int f()
{
A a;
a.gt();
a.pt();
return 0;
}
}

編譯命令:
gcc -shared -o sec.so secso.cpp -L. -lmy
這時候生成第二個.so文件,此時庫從一個類變成了一個c的接口.
拷貝到/usr/lib
下面開始調用:
test.c

#include "stdio.h"
#include "dlfcn.h"
#define SOFILE "sec.so"
int (*f)();
int main()
{
void *dp;
dp=dlopen(SOFILE,RTLD_LAZY);
f=dlsym(dp,"f");
f();
return 0;
}

編譯命令如下:
gcc -rdynamic -s -o myapp test.c
運行Z$./myapp

10
$

C調用C++的動態庫

假設C++動態庫中一個函數void world()函數需要被C使用到,同時C++動態庫的名稱為world.so,可以編寫一個臨時cpp程序,假設名稱為mid.cpp,內容如下:

#include<iostream>

void m_world()
{
world();
}
在mid.h文件中:

extern void world();

#ifdef __cplusplus
extern “C” {
#endif

void m_world();

#ifdef __cplusplus
}
#endif
編譯成新的動態庫:

g++ --shared -o libmid.so mid.cpp -lworld
C語言可以通過使用m_world()函數間接調用world()函數。

 

PS.

#ifdef __cplusplus當使用c++編譯器的時候會成立;

extern “c” {}含義是括號中的函數使用C編譯器編譯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM