[英]CPPYY/CTYPES passing array of strings as char* args[]
I only recently started using cppyy
and ctypes
, so this may be a bit of a silly question.我最近才开始使用
cppyy
和ctypes
,所以这可能是一个有点愚蠢的问题。 I have the following C++ function:我有以下 C++ function:
float method(const char* args[]) {
...
}
and from Python I want to pass args
as a list of strings, ie:从 Python 我想将
args
作为字符串列表传递,即:
args = *magic*
x = cppyy.gbl.method(args)
I have previously found this , so I used我以前发现过这个,所以我用
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)
and from Python:并来自 Python:
args = setParameters([b'hello', b'world'])
c_types.c_char_p
expects a bytes array. c_types.c_char_p
需要一个字节数组。 However, when calling x = cppyy.gbl.method(args)
I get但是,当调用
x = cppyy.gbl.method(args)
我得到
TypeError: could not convert argument 1 (could not convert argument to buffer or nullptr)
I'm not entirely sure why this would be wrong since the args
is a <__main__.c_char_p_Array_2>
object, which I believe should be converted to a const char* args[]
.我不完全确定为什么这是错误的,因为
args
是<__main__.c_char_p_Array_2>
object,我认为应该将其转换为const char* args[]
。
For the sake of having a concrete example, I'll use this as the .cpp
file:为了有一个具体的例子,我将使用它作为
.cpp
文件:
#include <cstdlib>
extern "C"
float method(const char* args[]) {
float sum = 0.0f;
const char **p = args;
while(*p) {
sum += std::atof(*p++);
}
return sum;
}
And I'll assume it was compiled with g++ method.cpp -fPIC -shared -o method.so
.我假设它是用
g++ method.cpp -fPIC -shared -o method.so
编译的。 Given those assumptions, here's an example of how you could use it from Python:鉴于这些假设,下面是一个示例,说明如何从 Python 使用它:
#!/usr/bin/env python3
from ctypes import *
lib = CDLL("./method.so")
lib.method.restype = c_float
lib.method.argtypes = (POINTER(c_char_p),)
def method(args):
return lib.method((c_char_p * (len(args) + 1))(*args))
print(method([b'1.23', b'45.6']))
We make a C array to hold the Python arguments.我们制作了一个 C 数组来保存 Python arguments。
len(args) + 1
makes sure there's room for the null pointer sentinel. len(args) + 1
确保 null 指针哨兵有空间。
ctypes does not have a public API that is usable from C/C++ for extension writers, so the handling of ctypes by cppyy is by necessity somewhat clunky. ctypes 没有公共的 API 可从 C/C++ 用于扩展编写器,因此 cppyy 对 ctypes 的处理必然有些笨拙。 What's going wrong, is that the generated ctypes array of
const char*
is of type const char*[2]
not const char*[]
and since cppyy does a direct type match for ctypes types, that fails.出了什么问题,生成的
const char*
的 ctypes 数组的类型是const char*[2]
而不是const char*[]
,并且由于 cppyy 对 ctypes 类型进行直接类型匹配,因此失败了。
As-is, some code somewhere needs to do a conversion of the Python strings to low-level C ones, and hold on to that memory for the duration of the call.照原样,某处的某些代码需要将 Python 字符串转换为低级 C 字符串,并在通话期间坚持使用 memory。 Me, personally, I'd use a little C++ wrapper, rather than having to think things through on the Python side.
就我个人而言,我会使用一点 C++ 包装器,而不必在 Python 方面考虑问题。 The point being that an
std::vector<std::string>
can deal with the necessary conversions (so no bytes
type needed, for example, but of course allowed if you want to) and it can hold the temporary memory.关键是
std::vector<std::string>
可以处理必要的转换(例如,因此不需要bytes
类型,但如果您愿意,当然允许)并且它可以保存临时 memory。
So, if you're given some 3rd party interface like this (putting it inline for cppyy only for the sake of the example):因此,如果您获得了这样的第 3 方接口(仅为了示例而将其内联用于 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;
}
""")
Then I'd generate a wrapper:然后我会生成一个包装器:
# 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());
}
}
""")
Then replace the original C API with the C++ version:然后用C++版本替换原来的C API:
# replace C version with C++ one for all Python users
cppyy.gbl.method = cppyy.gbl.MyCppAPI.method
and things will be as expected for any other person downstream:对于下游的任何其他人来说,事情将与预期的一样:
# now use it as expected
cppyy.gbl.method(["aap", "noot", "mies"])
All that said, obviously there is no reason why cppyy couldn't do this bit of wrapping automatically.综上所述,显然 cppyy 没有理由不能自动进行这一点包装。 I created this issue: https://bitbucket.org/wlav/cppyy/issues/235/automatically-convert-python-tuple-of
我创建了这个问题: https://bitbucket.org/wlav/cppyy/issues/235/automatically-convert-python-tuple-of
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.