将 python 列表包装为 unsigned char*

发布于 2024-11-28 01:55:28 字数 3157 浏览 1 评论 0原文

编辑:大家好!

我目前正在尝试从 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

仙女山的月亮 2024-12-05 01:55:28

您应该查看 模块数组。

特别是,您希望调用来自列表。如果您只是因为认为应该这样做而使用列表而不是字符串来传递,则可以使用一个字符串函数 fromstring。无论哪种方式,您都可以简单地使用格式说明符 'B' 初始化数组(注意大写)。

用法示例:

array ('B', [1, 2, 1, 0, 3, 6, 0, 6])

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:

array ('B', [1, 2, 1, 0, 3, 6, 0, 6])
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文