将 python 列表包装为 unsigned char*
编辑:大家好!
我目前正在尝试从 Python 访问 C++ 函数,当我尝试将 Python 列表作为参数传递给函数时,我遇到了问题。
这是我试图访问的 C++ 函数定义(用于向 PC/SC 阅读器发送命令):
SRpdu *SendAPDU(unsigned int uiAPDU, //Command
unsigned int ucLE, //Data expected for response
unsigned int ucLC, //Size of data buffer
unsigned char * pucDataBuf = 0); //data buffer
我的目标是从 python 调用此函数,如下例所示。目标是将列表 [1,2,3] 转换为 unsigned char * 缓冲区:
SendAPDU(0x01020304, 0, 3, [1, 2, 3])
灵感来自 SWIG 文档中的示例“33.9.1 Converting Python list to a char **” http://www.swig.org/Doc2.0/Python.html#Python_nn57,我定义遵循类型映射来处理 unsigned char *
但不幸的是,似乎没有使用类型映射。实际上,我只能在忽略最后一个参数或设置为 None 的情况下使用该函数。
Python 代码:
>>> SendAPDU(0x02000000, 2, 0)
[36864, [30, 240]] #This call is working
>>> SendAPDU(0x02000000, 2, 0, None)
[36864, [30, 240]] #Also working
然后,如果我尝试放置命令数据列表(替换前面示例中的 None),我会收到以下错误:
>>> SendAPDU(0x02000000, 2, 4, [1, 2, 3, 4]) # HERE IT'S NOT WORKING
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "EMReaderEx.py", line 196, in SendAPDU
def SendAPDU(self, *args): return _EMReaderEx.EMReaderEx_SendAPDU(self, *args)
NotImplementedError: Wrong number or type of arguments for overloaded function 'EMReaderEx_SendAPDU'.
Possible C/C++ prototypes are:
EMReaderEx::SendAPDU(unsigned int,unsigned int,unsigned int,unsigned char *)
EMReaderEx::SendAPDU(unsigned int,unsigned int,unsigned int)
EMReaderEx::SendAPDU(SApdu &)
我认为我们在这里是为了防止“参数类型错误”,所以我猜想未使用 typemap 是因为我认为(但不确定)由于参数格式不匹配而未调用该函数。所以主要问题是如何传递列表并确保该列表将被函数接受(并因此被类型映射捕获)?
我想我错过了一些东西,因为我没有找到任何可行的解决方案,而且它应该相对经常使用。
以下是 SWIG .i 文件中类型映射代码的代码:
%typemap(in) unsigned char * {
// Check if is a list
unsigned char *ucBuf = NULL;
if (PyList_Check($input) && PyList_Size($input) > 0) {
int size = PyList_Size($input);
int i = 0;
ucBuf = (unsigned char *) malloc((size+1)*sizeof(unsigned char));
for (i = 0; i < size; i++) {
PyObject *o = PyList_GetItem($input,i);
if (PyLong_Check(o))
ucBuf[i] = (unsigned char) PyLong_AsLong(o);
else {
PyErr_SetString(PyExc_TypeError,"list must contain integers");
free(ucBuf);
return NULL;
}
}
}
$1 = &ucBuf[0];
}
%typemap(freearg) unsigned char * {
if($1 != NULL)
free( $1);
}
In Resume, how to do the SWIG typemap to call C++ function :
SRpdu * SendAPDU(unsigned int uiAPDU, unsigned int ucLE, unsigned int ucLC, unsigned char * pucDataBuf);
Like that from python:
SendAPDU(0x02000000, 2, 4, [1, 2, 3, 4])
欢迎任何帮助 预先感谢
ps 抱歉,如果我的英语不好,那不是我的母语。
Edit : Hi all !!
I'm currently trying to access to C++ functions from Python and I'm facing to a problem when I try to pass Python list as argument to a function.
here is the C++ function definition I'm trying to access (used to send command to PC/SC reader) :
SRpdu *SendAPDU(unsigned int uiAPDU, //Command
unsigned int ucLE, //Data expected for response
unsigned int ucLC, //Size of data buffer
unsigned char * pucDataBuf = 0); //data buffer
My goal is to call this function as following from python like in example below. The goal is to convert the list [1,2,3] to a unsigned char * buffer :
SendAPDU(0x01020304, 0, 3, [1, 2, 3])
Insipired from example "33.9.1 Converting Python list to a char **" from SWIG documentation http://www.swig.org/Doc2.0/Python.html#Python_nn57, I defined following typemap to handle unsigned char *
but unfortunately it seems that the typemap is not used. Actually I can use the function only with last argument ignored or set to None.
Python code :
>>> SendAPDU(0x02000000, 2, 0)
[36864, [30, 240]] #This call is working
>>> SendAPDU(0x02000000, 2, 0, None)
[36864, [30, 240]] #Also working
Then if I try to put a list for data of the command (replacing None in previous example), I receive the following error :
>>> SendAPDU(0x02000000, 2, 4, [1, 2, 3, 4]) # HERE IT'S NOT WORKING
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "EMReaderEx.py", line 196, in SendAPDU
def SendAPDU(self, *args): return _EMReaderEx.EMReaderEx_SendAPDU(self, *args)
NotImplementedError: Wrong number or type of arguments for overloaded function 'EMReaderEx_SendAPDU'.
Possible C/C++ prototypes are:
EMReaderEx::SendAPDU(unsigned int,unsigned int,unsigned int,unsigned char *)
EMReaderEx::SendAPDU(unsigned int,unsigned int,unsigned int)
EMReaderEx::SendAPDU(SApdu &)
I think we are here in case of "Wrong type of argument", so I guess that the typemap is not used because I think, but not sure, that the function is not called because of the parameter format doesn't match. So the main question is how can I pass a list and be sure that will be accepted by the function (and therefore catched by the typemap) ?
I think I missed something because I didn't found any working solution for that, and it should relatively used often.
Here is the code of the typemap code in SWIG .i file:
%typemap(in) unsigned char * {
// Check if is a list
unsigned char *ucBuf = NULL;
if (PyList_Check($input) && PyList_Size($input) > 0) {
int size = PyList_Size($input);
int i = 0;
ucBuf = (unsigned char *) malloc((size+1)*sizeof(unsigned char));
for (i = 0; i < size; i++) {
PyObject *o = PyList_GetItem($input,i);
if (PyLong_Check(o))
ucBuf[i] = (unsigned char) PyLong_AsLong(o);
else {
PyErr_SetString(PyExc_TypeError,"list must contain integers");
free(ucBuf);
return NULL;
}
}
}
$1 = &ucBuf[0];
}
%typemap(freearg) unsigned char * {
if($1 != NULL)
free( $1);
}
In Resume, how to do the SWIG typemap to call C++ function :
SRpdu * SendAPDU(unsigned int uiAPDU, unsigned int ucLE, unsigned int ucLC, unsigned char * pucDataBuf);
Like that from python:
SendAPDU(0x02000000, 2, 4, [1, 2, 3, 4])
Any help is welcome
Thanks in advance
p.s. Sorry if my english is bad, it's not my native language.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您应该查看 模块数组。
特别是,您希望调用
来自列表
。如果您只是因为认为应该这样做而使用列表而不是字符串来传递,则可以使用一个字符串函数fromstring
。无论哪种方式,您都可以简单地使用格式说明符'B'
初始化数组(注意大写)。用法示例:
You should look into module arrays.
In particular, you are looking to call
fromlist
. If you are using a list to pass instead of a string just because you think that's what you should do, there is a string function available,fromstring
. Either way, you can simply initialize the array with format specifier'B'
(notice that capital).Example usage: