一、问题描述
博主想要实现的C++函数原型如下:
double* getInfo(int flag, double xyz[], char *xodrPath)
也就是需要传递参数为三个不同类型的参数,返回值为double类型的指针(数组)。
那么如何在Python中如何通过这个函数生成的.dll文件调用getInfo()函数,并将返回参数进行输出呢?
二、动态链接库(.dll)生成
在cmakeList.txt中添加语句:
add_library(libOdr SHARED getOdr.cpp)
target_link_libraries(libOdr ${ODRMANGER_LIB}/libproj.dll.a ${ODRMANGER_LIB}/libODrive.1.5.5.a)
上述语句中,libOdr
是指定生成的库文件的名字,注意其生成的时候会自动添加lib
关键字所以实际上生成的库文件全名是liblibOdr.dll
,如图所示:
SHARED
表示生成动态链接库也就是后缀名为.dll的库文件;若需要生成静态链接库关键字改为STATIC
即可。
getOdr.cpp
这是需要生成库文件的.cpp
文件,比如博主需要封装的getInfo()方法就是在.cpp文件中。
这条语句中,后边两个非必须项,是博主运行代码需要的链接库,如果.cpp中代码运行不需要链接库则无需添加,只需要target_link_libraries(libOdr)
即可。
上述文件编辑好后,clion可以直接ctrl+F9进行编译,即可在bin目录下看到生成的库文件;也可以
手动点击build进行编译生成库文件。
后续每次更新.cpp文件后都可以直接点Bulid下拉列表中Rebuild就可以重新生成.dll文件。
三、Python中引用
3.1 首先需要导入头文件:
from ctypes import *
3.2 库和函数调用
from ctypes import *
def getOdr(flag, pos, xodrPath):
# 调用该连接库
dll = CDLL('F:/libOdr.dll')
# 设定调用函数的返回数据类型,博主是长度为6的double指针数据类型,
dll.getInfo.restype = POINTER(c_double * 6)
# 将函数参数float数组pos(Python中为float)预处理为C++中的double类型数组
xyz3 = c_double * 3
xyz = xyz3()
for i in range(3):
xyz[i] = pos[i]
# 将函数参数预处理为C++中的char*类型(string),这里直接将长度设置为了100可灵活更改
xodr = (c_char * 100)(*bytes(xodrPath, "utf-8"))
cast(xodr, POINTER(c_char))
# 调用目标函数getInfo()
posInfo = dll.getInfo(flag, xyz, xodr)
result = []
for i in range(6):
# 将函数返回结果存储到result数组中
result.append(posInfo.contents[i])
return result
说明:
CDLL()
这个方法是调用链接库的方法(必要的),调用的时候在括号里添加库文件的路径即可,比如博主的.dll文件是在F盘。- 代码中的数字可根据实际情况灵活更改
- C++中的string类型必须通过char*类型通过如上代码进行处理
上述代码中头文件是引用的from ctypes import *
,也可以直接 import ctypes
,此时相关代码则需要加上ctypes.
,如下:
import ctypes
def getOdr(flag, pos, xodrPath):
dll = ctypes.CDLL('F:/libOdr.dll')
dll.getInfo.restype = ctypes.POINTER(ctypes.c_double * 6)
# char_p_test = bytes("中国", "utf8") # 汉字需用采用utf8编码
xyz3 = ctypes.c_double * 3
xyz = xyz3()
for i in range(3):
xyz[i] = pos[i]
xodr = (ctypes.c_char * 100)(*bytes(xodrPath, "utf-8"))
ctypes.cast(xodr, ctypes.POINTER(ctypes.c_char))
posInfo = dll.getInfo(flag, xyz, xodr)
result = []
for i in range(6):
result.append(posInfo.contents[i])
return result
main函数不变。
四、函数运行
main函数:
if __name__ == '__main__':
flag = 1
# pos = [5915.00, -2937.76, 0]
pos = [40, -1, 20.1659]
xodrPath = "D:/MCworkspace/odrParser/data/Germany_2018.xodr"
posInfo = getOdr(flag, pos, xodrPath)
for i in posInfo:
print(i)
图中红框部分数据即为调用函数后返回的6个double类型数据。