CTYPES和PYTHON3:不能返回长字符串

时间:2016-02-23 17:17:23

标签: python c++ ctypes

我有一个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字符串)。处理这种情况的最佳方法是什么?

非常感谢。

1 个答案:

答案 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")