我只是最近才开始使用cppyy
和ctypes
,所以这可能是一个愚蠢的问题。我具有以下C++函数:
float method(const char* args[]) {
...
}
从Python,我想将
args
作为字符串列表传递,即:args = *magic*
x = cppyy.gbl.method(args)
我以前已经找到this,所以我用了
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)
和从Python:
args = setParameters([b'hello', b'world'])
c_types.c_char_p
需要一个字节数组。但是,当调用x = cppyy.gbl.method(args)
时,我得到了TypeError: could not convert argument 1 (could not convert argument to buffer or nullptr)
我不完全确定为什么这会出错,因为
args
是<__main__.c_char_p_Array_2>
对象,我认为应该将其转换为const char* args[]
。 最佳答案
ctypes没有可用于扩展编写者的C/C++公共(public)公用API,因此cppyy对ctypes的处理必然有些笨拙。出问题的是,生成的const char*
的ctypes数组的类型为const char*[2]
而不是const char*[]
,并且由于cppyy对ctypes类型执行直接类型匹配,因此失败。
照原样,某处的某些代码需要将Python字符串转换为低级C字符串,并在调用期间保留该内存。我个人而言,我会使用一些C++包装器,而不是不得不从Python方面考虑问题。关键是std::vector<std::string>
可以处理必要的转换(例如,不需要bytes
类型,但是如果需要,当然可以允许),它可以保存临时内存。
因此,如果为您提供了一些这样的第三方接口(interface)(仅出于示例目的,将其内联为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;
}
""")
然后,我将生成一个包装器:
# 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());
}
}
""")
然后将原始的C API替换为C++版本:
# replace C version with C++ one for all Python users
cppyy.gbl.method = cppyy.gbl.MyCppAPI.method
下游的其他任何人都会得到预期的结果:
# now use it as expected
cppyy.gbl.method(["aap", "noot", "mies"])
综上所述,显然没有理由为什么cppyy不能自动进行这种自动包装。我创建了这个问题:https://bitbucket.org/wlav/cppyy/issues/235/automatically-convert-python-tuple-of
关于python - CPPYY/CTYPES将字符串数组作为char * args传递[],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/62009589/