python - 我无法使用 ctypes 访问 C++ 类属性

标签 python c++ ctypes

我正在使用 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/

相关文章:

python - 添加 pandas 数据框中的所有行

python - 知道一个项目在数组中的位置

c++ - 我的 GDB 有问题吗?

c++ - Armadillo SpMat<int> 与 Mat<int> 相比非常慢

python - ctypes 为 c_ulong 重新实现 rshift

python - ctypes 与 C 扩展

python - 我的脚本中处理器的使用情况可笑。如何优化呢?

python - 字典解包在三元表达式的一个分支中不起作用

python - 如何防止 Django fixtures 与现有数据冲突

c++ - 如何通过引用获取对象的大小?