注意,使用ctypes庫調用C++代碼時,由於C++相比於C多了函數重載的特性,因此一個函數不能僅僅使用其名字來確定,為了便於調用,每一個C++函數都需要增加標識符:
extern "C"示例代碼如下:
#include <iostream>
using namespace std;
typedef struct StructTest
{
char* name;
int age;
float score[2];
}StructData, *StructPtr;
class TestDataStructure
{
public:
int receiveInt(int a);
double receiveDouble(double d);
char receiveChar(char c);
char* receiveString(char* s);
StructData receiveStruct(StructData st);
StructPtr receiveStructPtr(StructPtr p);
StructPtr receiveStructArray(StructData vst[], int size);
};
int TestDataStructure::receiveInt(int a) {
cout << a << " in c++" << endl;
return a;
}
double TestDataStructure::receiveDouble(double d) {
cout << d << " in c++" << endl;
return d;
}
char TestDataStructure::receiveChar(char c) {
cout << c << " in c++" << endl;
return c;
}
char* TestDataStructure::receiveString(char* s) {
cout << s << " in c++" << endl;
return s;
}
StructData TestDataStructure::receiveStruct(StructData st) {
cout << st.name << " " << st.age << " " << st.score[2] << " in c++" << endl;
return st;
}
StructPtr TestDataStructure::receiveStructPtr(StructPtr p) {
cout << p->name << " " << p->age << " " << p->score[2] << " in c++" << endl;
return p;
}
StructPtr TestDataStructure::receiveStructArray(StructData vst[], int size) {
cout << vst[0].name << " in c++" << endl;
cout << vst[1].name << " in c++" << endl;
return &vst[0];
}
extern "C" {
TestDataStructure obj;
int passInt(int a) {
return obj.receiveInt(a);
}
double passDouble(double d){
return obj.receiveDouble(d);
}
char passChar(char c) {
return obj.receiveChar(c);
}
char* passString(char* s){
return obj.receiveString(s);
}
StructData passStruct(StructData st){
return obj.receiveStruct(st);
}
StructPtr passStructPtr(StructPtr p){
return obj.receiveStructPtr(p);
}
StructPtr passStructArray(StructData vst[], int size){
return obj.receiveStructArray(vst, size);
}
}
二、編譯動態連結庫使用如下命令編譯C++,可以將main.cpp文件編譯為libTest.so文件,保存目錄為根目錄。
g++ -o libTest.so -shared -fPIC main.cpp
三、python調用使用python的ctypes庫可以很方便地對其進行調用。
轉換原則如下:
所有的C++關鍵字及其特有的使用方式均不能出現在.h文件裡,.h中僅有C函數的包裝函數聲明
在class.cpp中實現對類的成員函數接口轉換的函數,包括對類內成員的讀寫函數get() and set()
如果要在包裝函數中要實例化對象,儘量用new constructor()的將對象的內存實例化在堆中,否則對象會被析構
記得在所有包含函數聲明的文件中加入以下關鍵字,聲明該函數為C函數,否則該函數的符號不會記錄在二進位文件中
C和python的數據格式需要對應,否則可能產生亂碼
上圖為數據轉換格式對應。python示例代碼如下:
import ctypes
lib = ctypes.cdll.LoadLibrary("/home/liangqian/PycharmProjects/Gauss/test_dataset/TestLib.so")
print("Test int io...")
func = lib.receiveInt
func.argtypes = [ctypes.c_int]
func.restype = ctypes.c_int
print(func(100))
print()
print("Test double io...")
func = lib.receiveDouble
func.argtypes = [ctypes.c_double]
func.restype = ctypes.c_double
print(func(3.14))
print()
print("Test char io...")
func = lib.receiveChar
func.argtypes = [ctypes.c_char]
func.restype = ctypes.c_char
print(func(ctypes.c_char(b'a')))
print()
print("Test string io...")
func = lib.receiveString
func.argtypes = [ctypes.c_char_p]
func.restype = ctypes.c_char_p
print(func(b"(This is a test string.)"))
print()
print("Test struct io...")
class Struct(ctypes.Structure):
_fields_ = [('name', ctypes.c_char_p),
('age', ctypes.c_int),
('score', ctypes.c_float * 3)]
lib.argtypes = [Struct]
lib.receiveStruct.restype = Struct
array = [85, 93, 95]
st = lib.receiveStruct(Struct(b'XiaoMing', 16, (ctypes.c_float * 3)(*array)))
print(str(st.name) + ' ' + str(st.age) + ' ' + str(st.score[0]) + ' in python')
print()
print('Test struct pointer io...')
lib.receiveStructPtr.restype = ctypes.POINTER(Struct)
lib.receiveStructPtr.argtypes = [ctypes.POINTER(Struct)]
p = lib.receiveStructPtr(Struct(b"XiaoHuang", 19, (ctypes.c_float * 3)(*array)))
print(str(p.contents.name) + ' ' + str(p.contents.age) + ' ' + str(p.contents.score[0]) + ' in python')
print()
print('Test struct array io...')
lib.receiveStructArray.restype = ctypes.POINTER(Struct)
lib.receiveStructArray.argtypes = [ctypes.ARRAY(Struct, 2), ctypes.c_int]
array = [Struct(b'student1', 19, (ctypes.c_float * 3)(91, 92, 93)),
Struct(b'student2', 18, (ctypes.c_float * 3)(88, 95, 92))]
p = lib.receiveStructArray(ctypes.ARRAY(Struct, 2)(*array), 2)
print(str(p.contents.name) + ' ' + str(p.contents.age) + ' ' + str(p.contents.score[2]) + ' in python')