Hike News
Hike News

[C++] C++生成DLL与LIB并调用

参考文章:

DLL 就是把一个C/CPP程序功能作为文件供其它程序调用

  • dll文件用于动态调用,在程序运行时调用,dll文件修改动能调用方程序也不需要重新编译
  • lib文件用于静态调用,在编译时与调用方一起编译链接,编译出来的程序会比动态调用大

1.创建想要作为DLL的C源文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// test.c

#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) int __stdcall add(int, int);
__declspec(dllexport) int __stdcall sum(int *nums, int size);
#ifdef __cplusplus
}
#endif

int __stdcall add(int a, int b)
return a + b;


int __stdcall sum(int *nums, int size)
{
int sum = 0;
for (int i = 0; i < size; i++)
sum += nums[i];
return sum;
}

这里定义了两个简单的函数,add和sum
之后通过编译器生成dll文件或lib文件,供主程序调用

2.动态调用方式:

  1. 生成dll

    1
    2
    3
    4
    5
    # GCC 编译器
    gcc -shared .\test.c -o test.dll
    # MSVC 编译器
    cl -c test.c
    link -DLL -out:test.dll test.obj
  2. 调用dll

    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
    // main.c
    #include <stdio.h>
    #include <windows.h>

    int main()
    {
    // 加载dll文件
    HMODULE hdll = LoadLibrary("test.dll");
    if (!hdll)
    {
    printf("未能加载DLL");
    return 0;
    }
    // 定义函数指针用于接收需要调用的函数
    typedef int (*FUNC_ADD_T)(int, int);
    typedef int (*FUNC_SUM_T)(int *, int);
    // 获取函数指针
    FUNC_ADD_T add = (FUNC_ADD_T)GetProcAddress(hdll, "add");
    FUNC_SUM_T sum = (FUNC_SUM_T)GetProcAddress(hdll, "sum");
    if (!add || !sum)
    {
    printf("未能加载函数");
    return 0;
    }
    int nums[5] = {1, 2, 3, 4, 5};
    printf("add函数测试 1 + 2 = %d\n", add(1, 2));
    printf("待累加数组为: ");
    for (int i = 0; i < 5; i++)
    printf("%d ", nums[i]);
    printf("\nsum函数测试输出结果: %d", sum(nums, 5));
    }
  3. 编译运行输出结果:

    出现乱码可以添加 --exec-charset=gbk编译选项

    1
    2
    3
    4
    $ gcc .\main.c -o .\main.exe && .\main.exe
    add函数测试 1 + 2 = 3
    待累加数组为: 1 2 3 4 5
    sum函数测试输出结果: 15

3.静态生成方式

  1. 生成lib

    1
    2
    3
    4
    # GCC生成lib
    gcc -c .\test.c -o test.lib
    # MSVC生成lib,obj,exp文件
    cl /Dld .\test.c
  2. 主函数调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // main.c
    #include <stdio.h>
    #include <windows.h>
    // 声明外部函数
    extern int add(int a, int b);
    extern int sum(int *nums, int size);
    int main()
    {
    int nums[5] = {1, 2, 3, 4, 5};
    printf("add函数测试 1 + 2 = %d\n", add(1, 2));
    printf("待累加数组为: ");
    for (int i = 0; i < 5; i++)
    printf("%d ", nums[i]);
    printf("\nsum函数测试输出结果: %d", sum(nums, 5));
    }
  3. 编译运行
    -L参数指定要调用的lib文件所在目录,
    -l参数指定要调用的lib文件名(不包含文件类型后缀)

    1
    2
    3
    4
    gcc .\main.c -L. -ltest -o main.exe && ./main.exe
    add函数测试 1 + 2 = 3
    待累加数组为: 1 2 3 4 5
    sum函数测试输出结果: 15

在Python中调用dll中的函数

  1. 调用dll中的函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # main.py
    import ctypes as C
    from os.path import abspath

    # 加载动态链接库
    dll = C.cdll.LoadLibrary(abspath("test.dll"))
    # 设置函数参数类型和返回值类型
    dll.sum.argtypes = [C.POINTER(C.c_int), C.c_int]
    dll.sum.restype = C.c_int
    # 生成测试数据
    arr = (C.c_int * 5)(1, 2, 3, 4, 5)
    # 调用函数
    result1 = dll.add(10, 20)
    result2 = dll.sum(arr, 5)
    print("add 输出结果: ", result1)
    print("待测试数组: ", arr[:])
    print("sum 输出结果: ", result1)
  2. 运行输出结果
    1
    2
    3
    4
    $ python main.py
    add 输出结果: 30
    待测试数组: [1, 2, 3, 4, 5]
    sum 输出结果: 30