python ctypes 数组数据损坏
python ctypes array data getting corrupted
我有以下文件:
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++ class 成员获得的字符串数组,但是,看起来数据最终以某种方式损坏了是我在执行 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, ...)
内设置断点,显示数据在该点仍然完好无损。
在 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&
也可以正常工作。
现在看清楚了,似乎是auto
在检测引用时犹豫不决,因此创建了局部变量,这不可避免地超出了范围,导致了UB。
Relevant part of the standard。另一种选择是使用 decltype(auto)
.
Relevant post.
我有以下文件:
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++ class 成员获得的字符串数组,但是,看起来数据最终以某种方式损坏了是我在执行 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, ...)
内设置断点,显示数据在该点仍然完好无损。
在 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&
也可以正常工作。
现在看清楚了,似乎是auto
在检测引用时犹豫不决,因此创建了局部变量,这不可避免地超出了范围,导致了UB。
Relevant part of the standard。另一种选择是使用 decltype(auto)
.
Relevant post.