CPPYY/CTYPES 将字符串数组作为 char* args[] 传递

R. *_*llo 5 c++ python arrays string ctypes

我最近才开始使用cppyyand ctypes,所以这可能是一个有点愚蠢的问题。我有以下 C++ 函数:

float method(const char* args[]) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

从 Python 我想args作为字符串列表传递,即:

args = *magic*
x = cppyy.gbl.method(args)
Run Code Online (Sandbox Code Playgroud)

我以前发现过这个,所以我使用了

def setParameters(strParamList):
    numParams    = len(strParamList)
    strArrayType = ct.c_char_p * numParams
    strArray     = strArrayType()
    for i, param in enumerate(strParamList):
        strArray[i] = param
    lib.SetParams(numParams, strArray)
Run Code Online (Sandbox Code Playgroud)

来自 Python:

args = setParameters([b'hello', b'world'])
Run Code Online (Sandbox Code Playgroud)

c_types.c_char_p需要一个字节数组。但是,当x = cppyy.gbl.method(args)我打电话时,我得到

TypeError: could not convert argument 1 (could not convert argument to buffer or nullptr)
Run Code Online (Sandbox Code Playgroud)

我不完全确定为什么这会是错误的,因为argsis 是一个<__main__.c_char_p_Array_2>对象,我认为应该将其转换为const char* args[].

Wim*_*sen 3

ctypes 没有可供扩展编写者从 C/C++ 使用的公共 API,因此 cppyy 对 ctypes 的处理必然有些笨拙。问题在于生成的 ctypes 数组的类型const char*不是const char*[2]const char*[]并且由于 cppyy 对 ctypes 类型进行直接类型匹配,因此失败。

按原样,某处的某些代码需要将 Python 字符串转换为低级 C 字符串,并在调用期间保留该内存。就我个人而言,我会使用一些 C++ 包装器,而不是必须在 Python 方面思考问题。要点是 anstd::vector<std::string>可以处理必要的转换(bytes例如,因此不需要类型,但如果您愿意的话当然可以)并且它可以保存临时内存。

因此,如果您获得像这样的第三方接口(仅为了示例而将其内联到 cppyy):

import cppyy

cppyy.cppdef("""
    float method(const char* args[], int len) {
        for (int i = 0; i < len; ++i)
            std::cerr << args[i] << " ";
        std::cerr << std::endl;
        return 42.f;
    }
""")
Run Code Online (Sandbox Code Playgroud)

然后我会生成一个包装器:

# write a C++ wrapper to hide C code
cppyy.cppdef("""
    namespace MyCppAPI {
       float method(const std::vector<std::string>& args) {
           std::vector<const char*> v;
           v.reserve(args.size());
           for (auto& s : args) v.push_back(s.c_str());
           return ::method(v.data(), v.size());
       }
    }
""")
Run Code Online (Sandbox Code Playgroud)

然后将原来的C API替换为C++版本:

# replace C version with C++ one for all Python users
cppyy.gbl.method = cppyy.gbl.MyCppAPI.method
Run Code Online (Sandbox Code Playgroud)

对于下游的任何其他人来说,事情都会如预期的那样:

# now use it as expected
cppyy.gbl.method(["aap", "noot", "mies"])
Run Code Online (Sandbox Code Playgroud)

综上所述,显然 cppyy 没有理由不能自动进行这一点包装。我创建了这个问题:https://bitbucket.org/wlav/cppyy/issues/235/automatically-convert-python-tuple-of