pythonint转换成c_uint
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pythonint转换成c_uint相关的知识,希望对你有一定的参考价值。
Python中的int类型可以转换为C语言中的uint类型,可以通过使用C语言的函数来实现。具体的实现方法如下:1. 首先,在Python中,可以使用int()函数将int类型转换为uint类型,如:int_val = int(uint_val)。
2. 然后,可以使用C语言的函数将Python中的int类型转换为C语言中的uint类型,如:uint_val = (uint)int_val。
3. 最后,可以使用C语言的函数将C语言中的uint类型转换为Python中的int类型,如:int_val = (int)uint_val。
因此,可以通过以上三个步骤,将Python中的int类型转换为C语言中的uint类型。希望我的回答对您有所帮助。 参考技术A 你可以使用Python内置的int()函数将pythonint转换成C语言的unsigned int(c_uint)类型,例如:int(pythonint, 0)。 参考技术B Python中没有c_uin这个数据类型,所以无法直接将Pythonint转换成c_uin。但是可以使用C语言的类型转换函数将Pythonint转换成c_uin。例如:
int pythonint = 123;
unsigned int c_uin = (unsigned int)pythonint; 参考技术C 从python int转换为CUint,需要用到Python的ctypes模块,例如:from ctypes import c_uint num = c_uint(python_int) 这样就可以将python int转换成CUint。 参考技术D 可以使用Python中的ctypes模块来实现Python int转换成C uint的操作,具体代码如下:
import ctypes
x = ctypes.c_uint(int(pythonint))
print(x.value)
构建 ctypes 类的简洁方式
【中文标题】构建 ctypes 类的简洁方式【英文标题】:Clean way of structuring ctypes class 【发布时间】:2015-09-27 18:51:54 【问题描述】:我已经定义了一个ctypes
类和一个相关的便利函数,如下所示:
class BNG_FFITuple(Structure):
_fields_ = [("a", c_uint32),
("b", c_uint32)]
class BNG_FFIArray(Structure):
_fields_ = [("data", c_void_p),
("len", c_size_t)]
# Allow implicit conversions from a sequence of 32-bit unsigned ints
@classmethod
def from_param(cls, seq):
return seq if isinstance(seq, cls) else cls(seq)
def __init__(self, seq, data_type = c_float):
array_type = data_type * len(seq)
raw_seq = array_type(*seq)
self.data = cast(raw_seq, c_void_p)
self.len = len(seq)
def bng_void_array_to_tuple_list(array, _func, _args):
res = cast(array.data, POINTER(BNG_FFITuple * array.len))[0]
return res
convert = lib.convert_to_bng
convert.argtypes = (BNG_FFIArray, BNG_FFIArray)
convert.restype = BNG_FFIArray
convert.errcheck = bng_void_array_to_tuple_list
drop_array = lib.drop_array
drop_array.argtypes = (POINTER(BNG_FFIArray),)
然后我定义一个简单的便利函数:
def f(a, b):
return [(i.a, i.b) for i in iter(convert(a, b))]
大部分都可以完美运行,但我有两个问题:
不够灵活;我希望能够使用c_float
而不是c_uint32
来实例化BNG_FFITuple
(所以字段是c_float
),反之亦然,所以BNG_FFIArray
data_type
是c_uint32
。不过,我不清楚如何做到这一点。
我想释放现在由 Python 拥有的内存,方法是将POINTER(BNG_FFIArray)
发送回我的 dylib(请参阅drop_array
- 我已经在我的 dylib 中定义了一个函数),但我不知道我应该在什么时候调用它。
有没有办法以一种更整洁、更 Python 的方式封装所有这些,也更安全?我担心如果没有以稳健的方式定义内存清理(在__exit__
?__del__
?)任何出现问题都会导致内存未释放
【问题讨论】:
您需要BNG_FFITuple
作为 FFI 参数,还是仅用于 Python?如果它只是在 Python 中使用,collections.namedtuple 会更好地为您服务。只需为int
和float
转换定义一个单独的errcheck
函数。您可以释放BNG_FFIArray.__del__
中的数组,但使用对lib.drop_array
的类引用作为BNG_FFIArray._drop_array
以避免在调用对象的__del__
终结器之前将模块拆卸设置lib
设置为None
出现问题。跨度>
我不确定我是否理解;我的 dylib 函数需要一个具有 data
和 len
字段的结构,并且具有适当的类型,但它不必被称为任何特定的。
您将结果转换为bng_void_array_to_tuple_list
中的BNG_FFITuple
数组。你有没有把BNG_FFITuple
传回你的图书馆?如果不是,则没有理由为此使用 ctypes 结构,而不是将结果转换为常规 Python tuple
或 namedtuple
。转换后,BNG_FFIArray
是对数组的唯一引用,因此可以使用其 __del__
终结器调用 drop_array
。
啊,好的。不,这是单程旅行;在bng_void_array_to_tuple_list
之后永远不会被使用。
您是否仅限于让您的库分配和返回内存,或者您是否可以计算返回数组的大小并从 Python 传递一个指向它的指针(以便 Python 拥有所有内存)?
【参考方案1】:
这是在被调用的 DLL 中分配返回数组的代码的修改版本。因为用纯 Python 更难测试,而且我不知道 rust,所以我为实际测试构建了一个俗气的 C 库:
#include <stdlib.h>
#include <stdio.h>
typedef struct FFIParams
int source_ints;
int len;
void * a;
void * b;
FFIParams, *FFIParamsPtr;
typedef int * intptr;
typedef float * floatptr;
void * to_float(FFIParamsPtr p)
floatptr result;
intptr a = p->a;
intptr b = p->b;
int i;
int size = sizeof(result[0]) * 2 * p->len;
result = malloc(size);
printf("Allocated %x bytes at %x\n", size, (unsigned int)result);
for (i = 0; i < p->len; i++)
result[i*2+0] = (float)(a[i]);
result[i*2+1] = (float)(b[i]);
return result;
void * to_int(FFIParamsPtr p)
intptr result;
floatptr a = p->a;
floatptr b = p->b;
int i;
int size = sizeof(result[0]) * 2 * p->len;
result = malloc(size);
printf("Allocated %x bytes at %x\n", size, (unsigned int)result);
for (i = 0; i < p->len; i++)
result[i*2+0] = (int)(a[i]);
result[i*2+1] = (int)(b[i]);
return result;
void * convert_to_bng(FFIParamsPtr p)
if (p->source_ints)
return to_float(p);
return to_int(p);
void free_bng_mem(void * data)
printf("Deallocating memory at %x\n", (unsigned int)data);
free(data);
这是调用它的 Python 代码:
from ctypes import c_uint32, c_float, c_size_t, c_void_p
from ctypes import Structure, POINTER, pointer, cast, cdll
from itertools import izip, islice
class _BNG_FFIParams(Structure):
_fields_ = [("source_ints", c_uint32),
("len", c_size_t),
("a", c_void_p),
("b", c_void_p)]
class _BNG_FFI(object):
int_type = c_uint32
float_type = c_float
_array_type = type(10 * int_type)
_lib = cdll.LoadLibrary('./testlib.so')
_converter = _lib.convert_to_bng
_converter.restype = c_void_p
_deallocate = _lib.free_bng_mem
_result_type = int_type: float_type,
float_type: int_type
def __init__(self):
my_params = _BNG_FFIParams()
self._params = my_params
self._pointer = POINTER(_BNG_FFIParams)(my_params)
def _getarray(self, seq, data_type):
# Optimization for pre-allocated correct array type
if type(type(seq)) == self._array_type and seq._type_ is data_type:
print("Optimized!")
return seq
return (data_type * len(seq))(*seq)
def __call__(self, a, b, data_type=float_type):
length = len(a)
if length != len(b):
raise ValueError("Input lengths must be same")
a, b = (self._getarray(x, data_type) for x in (a, b))
# This has the salutary side-effect of insuring we were
# passed a valid type
result_type = POINTER(length * 2 * self._result_type[data_type])
params = self._params
params.source_ints = data_type is self.int_type
params.len = length
params.a = cast(pointer(a), c_void_p)
params.b = cast(pointer(b), c_void_p)
resptr = self._converter(self._pointer)
result = cast(resptr, result_type).contents
evens = islice(result, 0, None, 2)
odds = islice(result, 1, None, 2)
result = list(izip(evens, odds))
self._deallocate(resptr)
return result
convert = _BNG_FFI()
if __name__ == '__main__':
print(convert([1.0, 2.0, 3.0], [4.0, 5.0, 6.0], c_float))
print(convert([1, 2, 3], [4, 5, 6], c_uint32))
print(convert([1, 2, 3], (c_uint32 * 3)(4, 5, 6), c_uint32))
这是我执行它时的结果:
Allocated 18 bytes at 9088468
Deallocating memory at 9088468
[(1L, 4L), (2L, 5L), (3L, 6L)]
Allocated 18 bytes at 908a6b8
Deallocating memory at 908a6b8
[(1.0, 4.0), (2.0, 5.0), (3.0, 6.0)]
Optimized!
Allocated 18 bytes at 90e1ae0
Deallocating memory at 90e1ae0
[(1.0, 4.0), (2.0, 5.0), (3.0, 6.0)]
这恰好是 32 位 Ubuntu 14.04 系统。我使用的是 Python 2.7,并使用 gcc --shared ffitest.c -o testlib.so -Wall
构建了库
【讨论】:
这个例子很简单,你不需要一个结构——你可以直接传递4个参数。但是您最初的问题有一个结构,我决定将其作为更复杂案例的示例。如果您想传递多个参数,只需执行此操作 - ctypes 不要求您在每个位置定义有效类型,它只是允许它,这当您将 ac 函数暴露给更高级别的代码时非常有用,但当您包装它并仅从一个地方调用它时就没那么有用了。【参考方案2】:由于您对 rust 方面有一定的控制权,因此最简单的做法是在调用之前从 Python 预先分配结果数组,并将所有内容传递到单个结构中。
下面的代码假定了这种修改,但也指定了如果你不能这样做,你将在哪里进行释放。
请注意,如果您进行这种封装,则不需要为库函数指定参数和结果处理等内容,因为您只是从一个地方调用实际函数,并且始终与相同类型的参数。
我不知道 rust(甚至我的 C 有点生锈),但下面的代码假设您重新定义 rust 以匹配类似这样的内容:
typedef struct FFIParams
int32 source_ints;
int32 len;
void * a;
void * b;
void * result;
FFIParams;
void convert_to_bng(FFIParams *p)
这里是 Python。最后一点——由于参数结构的重用,这不是线程安全的。如果需要,这很容易解决。
from ctypes import c_uint32, c_float, c_size_t, c_void_p
from ctypes import Structure, POINTER, pointer, cast
from itertools import izip, islice
_test_standalone = __name__ == '__main__'
if _test_standalone:
class lib(object):
@staticmethod
def convert_to_bng(ptr_params):
params = ptr_params.contents
source_ints = params.source_ints
types = c_uint32, c_float
if not source_ints:
types = reversed(types)
length = params.len
src_type, dst_type = types
src_type = POINTER(length * src_type)
dst_type = POINTER(length * 2 * dst_type)
a = cast(params.a, src_type).contents
b = cast(params.b, src_type).contents
result = cast(params.result, dst_type).contents
# Assumes we are converting int to float or back...
func = float if source_ints else int
result[0::2] = map(func, a)
result[1::2] = map(func, b)
class _BNG_FFIParams(Structure):
_fields_ = [("source_ints", c_uint32),
("len", c_size_t),
("a", c_void_p),
("b", c_void_p),
("result", c_void_p)]
class _BNG_FFI(object):
int_type = c_uint32
float_type = c_float
_array_type = type(10 * int_type)
# This assumes we want the result to be opposite type.
# Maybe I misunderstood this -- easily fixable if so.
_result_type = int_type: float_type, float_type: int_type
def __init__(self):
my_params = _BNG_FFIParams()
self._params = my_params
self._pointer = POINTER(_BNG_FFIParams)(my_params)
self._converter = lib.convert_to_bng
def _getarray(self, seq, data_type):
# Optimization for pre-allocated correct array type
if type(type(seq)) == self._array_type and seq._type_ is data_type:
print("Optimized!")
return seq
return (data_type * len(seq))(*seq)
def __call__(self, a, b, data_type=float_type):
length = len(a)
if length != len(b):
raise ValueError("Input lengths must be same")
a, b = (self._getarray(x, data_type) for x in (a, b))
# This has the salutary side-effect of insuring we were
# passed a valid type
result = (length * 2 * self._result_type[data_type])()
params = self._params
params.source_ints = data_type is self.int_type
params.len = length
params.a = cast(pointer(a), c_void_p)
params.b = cast(pointer(b), c_void_p)
params.result = cast(pointer(result), c_void_p)
self._converter(self._pointer)
evens = islice(result, 0, None, 2)
odds = islice(result, 1, None, 2)
result = list(izip(evens, odds))
# If you have to have the converter allocate memory,
# deallocate it here...
return result
convert = _BNG_FFI()
if _test_standalone:
print(convert([1.0, 2.0, 3.0], [4.0, 5.0, 6.0], c_float))
print(convert([1, 2, 3], [4, 5, 6], c_uint32))
print(convert([1, 2, 3], (c_uint32 * 3)(4, 5, 6), c_uint32))
【讨论】:
以上是关于pythonint转换成c_uint的主要内容,如果未能解决你的问题,请参考以下文章