【问题标题】:python ctypes array data getting corruptedpython ctypes数组数据被破坏
【发布时间】:2021-10-20 10:28:23
【问题描述】:

我有以下文件:

test.h:

extern "C" {

void* createTest();
void getStrings(void* test_ptr, char*** strings, size_t* length);

}

test.cpp:

#include <vector>
#include "test.h"

class Test {
public:
    Test() {
        strings.push_back("test1");
        strings.push_back("test2");
        strings.push_back("test3");
        strings.push_back("test4");
    }
    std::vector<char *>& getStrings() {
        return strings;
    }

private:
    std::vector<char *> strings;
};

void* createTest() {
    return reinterpret_cast<void *>(new Test());
}

void getStrings(void* test_ptr, char*** strings, size_t* length) {
    auto inst = reinterpret_cast<Test *>(test_ptr);
    auto strs = inst->getStrings();
    *strings = strs.data();
    *length = strs.size();
}

test.py:

from ctypes import *
lib = cdll.LoadLibrary("test.so")

test_ptr = c_void_p()
test_ptr = lib.createTest()

strs_arr = POINTER(c_char_p)()
strs_len = c_size_t()

lib.getStrings(test_ptr, byref(strs_arr), byref(strs_len))

for i in range(0, strs_len.value):
    print("var {}: data={}".format(i, strs_arr[i]))

我想要实现的是通过 python 检索从 c++ 类成员获得的字符串数组,但是,数据似乎最终以某种方式损坏,因为这是我在执行 python 文件时得到的:

var 0: data=None
var 1: data=b'\x04'
var 2: data=b'test3'
var 3: data=b'test4'

我正在使用以下指令进行编译:

clang++-12 -fPIC -g -c test.cpp -o test.o
clang++-12 -fPIC -g -shared test.o -o test.so

有人知道我做错了什么吗?我试过改变 ctypes 但我总是得到相同的结果。我也尝试过使用 gdb 进行调试,并在 getStrings(void* test_ptr, ...) 中设置断点显示到那时数据仍然完好无损。

【问题讨论】:

  • new 已经返回 void* afaik。我将void getStrings 中的前两行更改为Test*std::vector&lt;char*&gt; 而不是auto,它有效,但我不知道为什么
  • 更改为std::vector&lt;char *&gt; 对我不起作用,但更改为std::vector&lt;char *&gt;&amp; 对我有用。我认为这意味着 clang 认为 auto 不是对向量的引用,即使 inst-&gt;getStrings() 的返回类型是引用?我很困惑,但我的问题已经解决了,所以谢谢你:D
  • 抱歉错字我也打算写参考
  • @Lala5th 也许将其发布为答案?它似乎已经解决了 OP 的问题。

标签: python c++ arrays ctypes


【解决方案1】:

getStrings 中,auto 类型推导以某种方式失败。将其更改为:

void getStrings(void* test_ptr, char*** strings, size_t* length) {
    auto inst = reinterpret_cast<Test *>(test_ptr);
    std::vector<char*>& strs = inst->getStrings();
    *strings = strs.data();
    *length = strs.size();
}

似乎解决了这个问题。我发现将第二个参数的 auto 更改为 auto&amp; 也可以正常工作。

现在看清楚了,auto似乎在检测引用时犹豫不决,因此创建了局部变量,不可避免地超出范围并导致UB。

Relevant part of the standard。另一种选择是使用decltype(auto)

Relevant post.

【讨论】:

  • 它应该是 auto& strs = ... 否则 strs 是一个副本(临时对象),而不是 inst... 中向量的引用或您的显式解决方案。
猜你喜欢
  • 2015-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-20
  • 2023-03-04
  • 2023-02-17
  • 1970-01-01
  • 2016-01-21
相关资源
最近更新 更多