在方法 'my_print_hexbytes' 中,参数 1 类型 'uint32_t *'
in method 'my_print_hexbytes', argument 1 of type 'uint32_t *'
我正在通过 SWIG 编写 Python C 扩展,但在将二进制缓冲区传递给 C api 函数时感到沮丧。这是我的例子:
在utils.c
#include "utils.h"
void my_print_hexbytes(uint32_t *bytes, uint32_t bytes_len)
{
uint32_t i;
for(i = 0; i < bytes_len; i++)
printf("%02x", bytes[i]);
printf("\n");
}
在utils.h
#include "commons.h"
#ifndef XXXX_UTILS_H
#define XXXX_UTILS_H
void my_print_hexbytes(uint32_t *bytes, uint32_t bytes_len);
#endif /* XXXX_UTILS_H */
在commons.h
#ifndef XXXX_COMMONS_H
#define XXXX_COMMONS_H
....
....
#include <stdint.h>
....
....
#endif
在xxxx_for_py.i
%module xxxx_for_py
%{
#define SWIG_FILE_WITH_INIT
#include "commons.h"
#include "utils.h"
%}
%include "stdint.i"
void my_print_hexbytes(uint32_t *bytes, uint32_t bytes_len);
第一次尝试
编译出 _xxxx_for_py.so
后,我尝试在 IPython 中测试它:
In [1]: import xxxx_for_py
In [2]: from ctypes import *
In [3]: a_t = c_uint * 2
In [4]: a = a_t(0x1, 0x2)
In [5]: xxxx_for_py.my_print_hexbytes(a, 2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-3c023fcf8b04> in <module>()
----> 1 xxxx_for_py.my_print_hexbytes(a, 2)
TypeError: in method 'my_print_hexbytes', argument 1 of type 'uint32_t *'
那时候我不知道怎么处理这个案子。我尝试将 a
更改为 bytearray
但它没有用。
不确定是否有人可以帮助我解决这个问题。谢谢!
第二次尝试
感谢@Petesh 的评论。我已经尝试将 a
转换为 POINTER(c_uint)
但仍然无法正常工作:(
In [5]: xxxx_for_py.my_print_hexbytes(cast(a, POINTER(c_uint)), 2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-2abb9dae484d> in <module>()
----> 1 xxxx_for_py.my_print_hexbytes(cast(a, POINTER(c_uint)), 2)
TypeError: in method 'my_print_hexbytes', argument 1 of type 'uint32_t *'
第三次尝试
在 SWIG 文档中被 Unbounded Array section 引用,我将 carray.i
添加到 xxxx_for_py.i
在xxxx_for_py.i
....
....stdint.i"
%include "carrays.i"
%array_class(uint32_t, uint32Array)
....
重新编译加载后.so
,还是一样的错误
In [1]: import xxxx_for_py
In [2]: a = xxxx_for_py.uint32Array(2)
In [3]: a[0] = 0x0
In [4]: a[1] = 0x1
In [5]: xxxx_for_py.my_print_hexbytes(a, 2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-3c023fcf8b04> in <module>()
----> 1 xxxx_for_py.my_print_hexbytes(a, 2)
TypeError: in method 'my_print_hexbytes', argument 1 of type 'uint32_t *'
第四次尝试
当时一周后,用户Nethanel post an 。虽然还是不行,但是可以帮我找到一些有趣的东西。
发现你的问题,因为同样的问题。
不幸的是,SWIG 似乎不支持高级类型:在 http://www.swig.org/Doc3.0/Library.html#Library_carrays 中,在 array_class 宏的描述之后,写着:"When using this macro, type is restricted to a simple type name like int or float."
我也试过用"unsigned int"失败了。
最后我的解决方法是使用 C++ 向量而不是 uint32_t 指针,这里是 swig 文件的相关部分:
%include "stdint.i"
%include "std_vector.i"
namespace std {
%template(vectoruint32) vector<uint32_t>;
};
h 文件的一部分:
#include <vector>
static uint32_t foo(std::vector<uint32_t> v) {return v[1] - v[0];}
python:
import example
l = [1, 2, 3, 4]
example.foo(l)
希望对您有所帮助
经过简单的测试,我自己找到了解决办法。详情见本文http://au9ustine.github.io/wiki/crypto/cuda/swig.html#typeerror-in-method-xxxx-argument-y-of-type-zzzz(2017-01-13更新:此页已损坏,我将把该页内容移至此处)
简要解剖
继续尝试测试 Python 将二进制缓冲区传递给普通 C 模块的代码(即由 gcc 编译的库,没有额外的依赖项)。内部结构可能如下所示:
integer list -> array/struct -> raw string -> C function parameter
来自 create_string_buffer 的一些描述。通过create_string_buffer
,Python可以提供这样的功能,为当前变量动态分配内存片以供使用。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
size_t
print_int_buf(void *src, size_t len)
{
size_t i = 0;
uint32_t *int_ptr = (uint32_t *)src;
for (i = 0; i < len; i++) {
printf("%p: %x\n", int_ptr + i, int_ptr[i]);
}
return i;
}
如果编译为名为 my_ext_lib.so
的共享库,代码可以在 Python
中加载
import ctypes
from ctypes import *
import array
my_ext = ctypes.CDLL('./my_ext_lib.so')
buf = create_string_buffer(array.array('I', range(0x10)).tostring())
my_ext_lib.print_int_buf(buf, 0x10)
它确实奏效了。
Though ctype and SWIG are quite different approaches for
interoperating integration between Python and C, I use ctype code
here to elaborate the basic mechanism and its working way of passing
parameters to a compiled module (both for Python module and trivial
C shared library module).
临时解决方案
既然在我看来显着的区别是函数接口(或方法签名),为什么不将其更改为 void *
而不是 uint32_t *
? (虽然不是最好的办法,但不失为一个临时的收容方案)
我将方法 my_print_hexbytes
的 uint32_t *
替换为 void *
,并附加了依赖项 cdata.i
(我不确定它是否有效,但为了安全起见,它已经添加)。所以下面列出了更改,最终它显示了预期的结果。
utils.c
#include "utils.h"
...
void
my_print_hexbytes(void *bytes, size_t bytes_len)
{
size_t i = 0;
uint32_t *int_buf_ptr = (uint32_t *)bytes;
for(i = 0; i < bytes_len; i++)
printf("%02x", int_buf_ptr[i]);
printf("\n");
}
header utils.h
#include "commons.h"
#ifndef XXXX_UTILS_H
#define XXXX_UTILS_H
...
void my_print_hexbytes(void *bytes, size_t bytes_len);
#endif /* XXXX_UTILS_H */
xxxx_for_py.i
%module xxxx_for_py
%{
#define SWIG_FILE_WITH_INIT
#include "commons.h"
#include "utils.h"
%}
%include "stdint.i"
%include "carrays.i"
%include "cdata.i"
%array_class(uint32_t, uint32Array)
...
void my_print_hexbytes(void *bytes, size_t bytes_len);
调用Python中的方法,就像:
In [1]: import xxxx_for_py
In [2]: a = xxxx_for_py.uint32Array(0x10)
In [3]: for i in range(0x10):
...: a[i] = i
...:
In [4]: xxxx_for_py.my_print_hexbytes(a, 0x10)
000102030405060708090a0b0c0d0e0f
我有一个非常简单的案例,但仍然出现此错误。这个问题的修复有效:
Swig python - c++ how to use type int8_t
我在.i文件的模块def后面直接添加了%include "stdint.i"
我正在通过 SWIG 编写 Python C 扩展,但在将二进制缓冲区传递给 C api 函数时感到沮丧。这是我的例子:
在utils.c
#include "utils.h"
void my_print_hexbytes(uint32_t *bytes, uint32_t bytes_len)
{
uint32_t i;
for(i = 0; i < bytes_len; i++)
printf("%02x", bytes[i]);
printf("\n");
}
在utils.h
#include "commons.h"
#ifndef XXXX_UTILS_H
#define XXXX_UTILS_H
void my_print_hexbytes(uint32_t *bytes, uint32_t bytes_len);
#endif /* XXXX_UTILS_H */
在commons.h
#ifndef XXXX_COMMONS_H
#define XXXX_COMMONS_H
....
....
#include <stdint.h>
....
....
#endif
在xxxx_for_py.i
%module xxxx_for_py
%{
#define SWIG_FILE_WITH_INIT
#include "commons.h"
#include "utils.h"
%}
%include "stdint.i"
void my_print_hexbytes(uint32_t *bytes, uint32_t bytes_len);
第一次尝试
编译出 _xxxx_for_py.so
后,我尝试在 IPython 中测试它:
In [1]: import xxxx_for_py
In [2]: from ctypes import *
In [3]: a_t = c_uint * 2
In [4]: a = a_t(0x1, 0x2)
In [5]: xxxx_for_py.my_print_hexbytes(a, 2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-3c023fcf8b04> in <module>()
----> 1 xxxx_for_py.my_print_hexbytes(a, 2)
TypeError: in method 'my_print_hexbytes', argument 1 of type 'uint32_t *'
那时候我不知道怎么处理这个案子。我尝试将 a
更改为 bytearray
但它没有用。
不确定是否有人可以帮助我解决这个问题。谢谢!
第二次尝试
感谢@Petesh 的评论。我已经尝试将 a
转换为 POINTER(c_uint)
但仍然无法正常工作:(
In [5]: xxxx_for_py.my_print_hexbytes(cast(a, POINTER(c_uint)), 2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-2abb9dae484d> in <module>()
----> 1 xxxx_for_py.my_print_hexbytes(cast(a, POINTER(c_uint)), 2)
TypeError: in method 'my_print_hexbytes', argument 1 of type 'uint32_t *'
第三次尝试
在 SWIG 文档中被 Unbounded Array section 引用,我将 carray.i
添加到 xxxx_for_py.i
在xxxx_for_py.i
....
....stdint.i"
%include "carrays.i"
%array_class(uint32_t, uint32Array)
....
重新编译加载后.so
,还是一样的错误
In [1]: import xxxx_for_py
In [2]: a = xxxx_for_py.uint32Array(2)
In [3]: a[0] = 0x0
In [4]: a[1] = 0x1
In [5]: xxxx_for_py.my_print_hexbytes(a, 2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-3c023fcf8b04> in <module>()
----> 1 xxxx_for_py.my_print_hexbytes(a, 2)
TypeError: in method 'my_print_hexbytes', argument 1 of type 'uint32_t *'
第四次尝试
当时一周后,用户Nethanel post an
发现你的问题,因为同样的问题。
不幸的是,SWIG 似乎不支持高级类型:在 http://www.swig.org/Doc3.0/Library.html#Library_carrays 中,在 array_class 宏的描述之后,写着:"When using this macro, type is restricted to a simple type name like int or float."
我也试过用"unsigned int"失败了。
最后我的解决方法是使用 C++ 向量而不是 uint32_t 指针,这里是 swig 文件的相关部分:
%include "stdint.i"
%include "std_vector.i"
namespace std {
%template(vectoruint32) vector<uint32_t>;
};
h 文件的一部分:
#include <vector>
static uint32_t foo(std::vector<uint32_t> v) {return v[1] - v[0];}
python:
import example
l = [1, 2, 3, 4]
example.foo(l)
希望对您有所帮助
经过简单的测试,我自己找到了解决办法。详情见本文http://au9ustine.github.io/wiki/crypto/cuda/swig.html#typeerror-in-method-xxxx-argument-y-of-type-zzzz(2017-01-13更新:此页已损坏,我将把该页内容移至此处)
简要解剖
继续尝试测试 Python 将二进制缓冲区传递给普通 C 模块的代码(即由 gcc 编译的库,没有额外的依赖项)。内部结构可能如下所示:
integer list -> array/struct -> raw string -> C function parameter
来自 create_string_buffer 的一些描述。通过create_string_buffer
,Python可以提供这样的功能,为当前变量动态分配内存片以供使用。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
size_t
print_int_buf(void *src, size_t len)
{
size_t i = 0;
uint32_t *int_ptr = (uint32_t *)src;
for (i = 0; i < len; i++) {
printf("%p: %x\n", int_ptr + i, int_ptr[i]);
}
return i;
}
如果编译为名为 my_ext_lib.so
的共享库,代码可以在 Python
import ctypes
from ctypes import *
import array
my_ext = ctypes.CDLL('./my_ext_lib.so')
buf = create_string_buffer(array.array('I', range(0x10)).tostring())
my_ext_lib.print_int_buf(buf, 0x10)
它确实奏效了。
Though ctype and SWIG are quite different approaches for interoperating integration between Python and C, I use ctype code here to elaborate the basic mechanism and its working way of passing parameters to a compiled module (both for Python module and trivial C shared library module).
临时解决方案
既然在我看来显着的区别是函数接口(或方法签名),为什么不将其更改为 void *
而不是 uint32_t *
? (虽然不是最好的办法,但不失为一个临时的收容方案)
我将方法 my_print_hexbytes
的 uint32_t *
替换为 void *
,并附加了依赖项 cdata.i
(我不确定它是否有效,但为了安全起见,它已经添加)。所以下面列出了更改,最终它显示了预期的结果。
utils.c
#include "utils.h"
...
void
my_print_hexbytes(void *bytes, size_t bytes_len)
{
size_t i = 0;
uint32_t *int_buf_ptr = (uint32_t *)bytes;
for(i = 0; i < bytes_len; i++)
printf("%02x", int_buf_ptr[i]);
printf("\n");
}
header utils.h
#include "commons.h"
#ifndef XXXX_UTILS_H
#define XXXX_UTILS_H
...
void my_print_hexbytes(void *bytes, size_t bytes_len);
#endif /* XXXX_UTILS_H */
xxxx_for_py.i
%module xxxx_for_py
%{
#define SWIG_FILE_WITH_INIT
#include "commons.h"
#include "utils.h"
%}
%include "stdint.i"
%include "carrays.i"
%include "cdata.i"
%array_class(uint32_t, uint32Array)
...
void my_print_hexbytes(void *bytes, size_t bytes_len);
调用Python中的方法,就像:
In [1]: import xxxx_for_py
In [2]: a = xxxx_for_py.uint32Array(0x10)
In [3]: for i in range(0x10):
...: a[i] = i
...:
In [4]: xxxx_for_py.my_print_hexbytes(a, 0x10)
000102030405060708090a0b0c0d0e0f
我有一个非常简单的案例,但仍然出现此错误。这个问题的修复有效: Swig python - c++ how to use type int8_t
我在.i文件的模块def后面直接添加了%include "stdint.i"