用c扩展python时,如何处理任意大小的整数?

问题描述 投票:0回答:3

Python/C API 手册提到了从⁽1⁾ 到 ⁽²⁾ void 指针的转换函数,这似乎是在 C 中使用任意长度 python 整数的唯一方法。
(1) :

PyLong_FromVoidPtr()
并使用
0&
 格式化 
Py_BuildValue()
(2) :
PyLong_AsVoidPtr()
和格式
0
0&
0!
PyArg_…Parse…()

但是,我在手册中没有找到⁽³⁾,任何关于如何使用这些 void 指针在 C 中对任意长整数执行任何操作的指示。
(3) : 我尝试搜索“voidptr”、“void *”和“0&”,但还没有彻底读完。

我在哪里可以找到有关其内部结构或基元的信息以对其进行计算?

python c python-3.x long-integer arbitrary-precision
3个回答
6
投票

实际上,这些函数并不是“指向任意大整数的指针”,而实际上只是将整数值作为

void *
指针,如所示,转换为类型
void *
。请参阅
PyLong_FromVoidPtr
PyLong_AsVoidPtr
的实现。它的存在只是为了让你可以在 Python 中保存任意指针,确保转换正确完成。

据我所知,从 Python 中获取任意长整数的最实用方法是使用

int.to_bytes
int.from_bytes
。实际上有一个内部 API
_PyLong_FromByteArray
/
_PyLong_AsByteArray
可供您使用。请参阅相关问题 Python 扩展 - 高效构造和检查大整数

注意:有趣的是,似乎没有任何官方或其他形式的 C API 可以告诉 Python 整数值的位或字节长度。在 Python 中,有

int.bit_length
,但它似乎没有映射到任何公开可用的函数。


2
投票

Include/longintrepr.h
中有文档:

/* Parameters of the integer representation.  There are two different
   sets of parameters: one set for 30-bit digits, stored in an unsigned 32-bit
   integer type, and one set for 15-bit digits with each digit stored in an
   unsigned short.  The value of PYLONG_BITS_IN_DIGIT, defined either at
   configure time or in pyport.h, is used to decide which digit size to use.

   Type 'digit' should be able to hold 2*PyLong_BASE-1, and type 'twodigits'
   should be an unsigned integer type able to hold all integers up to
   PyLong_BASE*PyLong_BASE-1.  x_sub assumes that 'digit' is an unsigned type,
   and that overflow is handled by taking the result modulo 2**N for some N >
   PyLong_SHIFT.  The majority of the code doesn't care about the precise
   value of PyLong_SHIFT, but there are some notable exceptions:

   - long_pow() requires that PyLong_SHIFT be divisible by 5

   - PyLong_{As,From}ByteArray require that PyLong_SHIFT be at least 8

   - long_hash() requires that PyLong_SHIFT is *strictly* less than the number
     of bits in an unsigned long, as do the PyLong <-> long (or unsigned long)
     conversion functions

   - the Python int <-> size_t/Py_ssize_t conversion functions expect that
     PyLong_SHIFT is strictly less than the number of bits in a size_t

   - the marshal code currently expects that PyLong_SHIFT is a multiple of 15

   - NSMALLNEGINTS and NSMALLPOSINTS should be small enough to fit in a single
     digit; with the current values this forces PyLong_SHIFT >= 9

  The values 15 and 30 should fit all of the above requirements, on any
  platform.
*/

int
的长度是可变长度部分的长度乘以15/16(以位为单位) - 数字要么是uint32_t
#if PYLONG_BITS_IN_DIGIT == 30
中的
30位,要么是uint16_t
中的
15位;长物体的结构是

struct _longobject {
    PyObject_VAR_HEAD
    digit ob_digit[1];
};

有一个成员 ob_size 会告诉大小(以字节为单位) - 因此,如果

PYLONG_BITS_IN_DIGIT
是 30,则
ob_digit
是一个由
ob_size / sizeof(uint32_t)
uint32_t
组成的数组,每个 30 位都是有效的;否则
ob_digit
ob_size / sizeof(uint16_t)
uint16_t
的数组,每个数字存储 15 个有效位。

这都是

Include/longintrepr.h
的一部分,但它们仅被揭示
#ifndef Py_LIMITED_API


0
投票

有人能找到解决这个问题的方法吗? 我想将 Python 整数转换为 C int 数组。 如果您能找到,请提供示例代码。

© www.soinside.com 2019 - 2024. All rights reserved.