zoukankan      html  css  js  c++  java
  • 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 ");
            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 ",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编译器编译。

  • 相关阅读:
    LeetCode 977 有序数组的平方
    LeetCode 24 两两交换链表中的节点
    LeetCode 416 分割等和子集
    LeetCode 142 环形链表II
    LeetCode 106 从中序与后序遍历序列构造二叉树
    LeetCode 637 二叉树的层平均值
    LeetCode 117 填充每个节点的下一个右侧节点
    LeetCode 75 颜色分类
    redhat 7.4 挂载ntfs格式的u盘并且使用
    redhat 查看CPU frequency scaling(CPU频率缩放)
  • 原文地址:https://www.cnblogs.com/ArcherWuAIot/p/14598282.html
Copyright © 2011-2022 走看看