我有一个C ++代码,我为其创建了一个python.ctypes包装器。除非返回的字符串很长,否则它的效果非常好。 C代码示例:
extern "C" {
const char * hallo(char * nome)
{
string str(nome);
str = "hallo " + str;
for(int i=0; i<100; i++)
str += " new content";
return str.c_str();
}
我的python代码是:
self.lib = ctypes.CDLL(LIB_PATH)
self.lib.hallo.restype = ctypes.c_char_p
self.lib.hallo.argtypes =[ctypes.c_char_p]
j = self.lib.hallo('my name'.encode())
print('INIT: ' + j.decode())
字符串大小是动态的(事实上,它将是一个json字符串)。处理这种情况的最佳方法是什么?
非常感谢。
答案 0 :(得分:4)
这里的问题是,当你return str.c_str()
时,你正在返回一个指向堆栈分配内存的指针,该内存在从C ++代码返回时被覆盖。
可能的解决方法是使用static string str
,例如:
#include <string>
#include <sstream>
extern "C" {
const char * hallo(char * nome)
{
static std::string str;
std::stringstream stream;
stream << "hallo " << nome;
for(int i=0; i<100; i++)
stream << " new content";
str = stream.str();
return str.c_str();
}
}
虽然这会阻止您从多个线程调用例程。
如果你想能够从多个地方调用它,你应该把一个参数指针指向一些内存,并传入一个从ctypes.create_string_buffer
创建的指针缓冲区(希望它具有正确的大小)情况)。
例如:
#include <string>
#include <sstream>
extern "C" {
const char * hallo(char * nome, char *writebuffer, unsigned int buffersize)
{
std::string str(nome);
str = "hallo " + str;
for(int i=0; i<100; i++)
str += " new content";
if (str.size() < buffersize) {
str.copy(writebuffer, buffersize);
return writebuffer;
} else {
return 0;
}
}
}
然后使用这个库的一些示例python代码;传入128k缓冲区:
import ctypes
lib = ctypes.cdll.LoadLibrary(LIB_PATH)
lib.hallo.restype = ctypes.c_char_p
lib.hallo.argtypes =[ctypes.c_char_p, ctypes.c_char_p, ctypes.c_uint]
allocation = ctypes.create_string_buffer(128 * 1024)
j = lib.hallo('my name'.encode(), allocation, 128 * 1024)
if j is not None:
print('INIT: ' + allocation.value)
else:
print("Buffer was too small")