我正在使用 ctypes 为 C++ 库开发一种 Python API。到目前为止,一切正常。但是,我将我的操作系统从 Ubuntu 20.4 LTS 升级到 22.04(现在使用 Python3.10.6 和 g++ 11.3.0,但即使使用 g++ 9.x.x,也会出现以下问题)。
我现在遇到的问题是,每当我想访问 C++ 对象的属性时,我都会收到核心转储错误。奇怪的是(对我来说)它在我使用 valgrind 调试时运行得非常好。这是一个测试用例,可以说明我在说什么。
首先,我的 .h (moncc.h
) 和我的 .cc (moncc.cc
) 文件:
class test {
public:
test() : value(0) { ; }
void set_value(int lval);
void print();
protected:
int value;
};
#include <iostream>
#include "moncc.h"
void test::set_value(int val)
{
printf("Here1\n");
value = val;
printf("Here2\n");
}
void test::print()
{
printf("valeur : %d\n",value);
}
extern "C"
{
test* CreateTest()
{
return new test();
}
void set_value(test* obj, int val)
{
obj->set_value(val);
}
void print(test* obj)
{
obj->print();
}
}
接下来,我编译创建 test.so
库:
g++ -c -Wall -lstdc++ -fPIC moncc.cc -o moncc.o
gcc moncc.o -shared -o test.so
wrapper.py
文件定义了与之前的extern "C"
函数的接口(interface):
#!/usr/bin/env python
# coding: utf-8
import ctypes
lib = ctypes.CDLL("test.so")
class test(object):
def __init__(self):
self.obj = lib.CreateTest()
def set_value(self,val):
lib.set_value(self.obj,val)
def print(self):
lib.print(self.obj)
最后是我的 main.py
文件:
#!/usr/bin/env python
# coding: utf-8
from wrapper import *
mon_obj = test()
mon_obj.set_value(5)
mon_obj.print()
我在 LD_LIBRARY_PATH
中添加了 test.so
所在的目录,结果如下:
python3 main.py
Here1
Erreur de segmentation (core dumped)
(抱歉,这是法语)
但是,
valgrind python3 cas.py
==245604== Memcheck, a memory error detector
==245604== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==245604== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==245604== Command: python3 main.py
==245604==
Here1
Here2
valeur : 5
==245604==
==245604== HEAP SUMMARY:
==245604== in use at exit: 656,376 bytes in 179 blocks
==245604== total heap usage: 2,348 allocs, 2,169 frees, 3,568,710 bytes allocated
==245604==
==245604== LEAK SUMMARY:
==245604== definitely lost: 0 bytes in 0 blocks
==245604== indirectly lost: 0 bytes in 0 blocks
==245604== possibly lost: 568 bytes in 1 blocks
==245604== still reachable: 655,808 bytes in 178 blocks
==245604== suppressed: 0 bytes in 0 blocks
==245604== Rerun with --leak-check=full to see details of leaked memory
==245604==
==245604== For lists of detected and suppressed errors, rerun with: -s
==245604== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
有什么想法吗?我真的不明白...
最佳答案
为ctypes
调用的函数设置.argtypes
和.restype
。由于返回值默认为 c_int
(32 位整数),CreateTest
返回的 64 位指针被截断。
工作代码:
测试.cpp
#include <stdio.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
class test {
int value;
public:
test() : value(0) { printf("Created test\n"); }
~test() { printf("Destroyed test\n"); }
void set_value(int val) { value = val; }
void print() { printf("value: %d\n",value); }
};
extern "C" {
API test* CreateTest() {
return new test();
}
API void DestroyTest(test* obj) {
delete obj;
}
API void set_value(test* obj, int val) {
obj->set_value(val);
}
API void print(test* obj) {
obj->print();
}
}
测试.py
import ctypes as ct
class Test:
def __init__(self):
self.obj = lib.CreateTest()
def __del__(self):
lib.DestroyTest(self.obj)
def set_value(self,val):
lib.set_value(self.obj, val)
def print(self):
lib.print(self.obj)
lib = ct.CDLL('./test')
class PTEST(ct.c_void_p): pass # opaque pointer aids type-checking
lib.CreateTest.argtypes = ()
lib.CreateTest.restype = PTEST
lib.DestroyTest.argtypes = PTEST,
lib.DestroyTest.restype = None
lib.set_value.argtypes = PTEST, ct.c_int
lib.set_value.restype = None
lib.print.argtypes = PTEST,
lib.print.restype = None
mon_obj = Test()
mon_obj.set_value(5)
mon_obj.print()
输出:
Created test
value: 5
Destroyed test
关于python - 我无法使用 ctypes 访问 C++ 类属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74414406/