CTYPES和PYTHON3:无法返回长字符串

Jul*_*ENS 0 c++ python 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();
}
Run Code Online (Sandbox Code Playgroud)

我的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())
Run Code Online (Sandbox Code Playgroud)

字符串大小是动态的(实际上,它将是json字符串)。处理这种情况的最佳方法是什么?

非常感谢。

Pet*_*esh 5

这里的问题是,当您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();
}

}
Run Code Online (Sandbox Code Playgroud)

尽管这将阻止您从多个线程调用例程。

如果希望能够从多个位置调用它,则可能应该将参数指针带到某些内存,并传入从其创建的指针缓冲区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;
    }
}

}
Run Code Online (Sandbox Code Playgroud)

然后是一些使用该库的示例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")
Run Code Online (Sandbox Code Playgroud)