【问题标题】:python passing integer to c++ 64bit library: varying sizespython将整数传递给c ++ 64位库:不同的大小
【发布时间】:2015-11-04 22:39:21
【问题描述】:

我正在 python 软件(也是 64 位)中加载 64 位 c++ 库。我注意到的第一个问题是通过以下协议传递给库的一些整数大小不合适:

Python 方面:

c_int = c_int64
polynomialFittingDLL.loadComputationFromPython.restype = None
polynomialFittingDLL.loadComputationFromPython.argtypes = [c_void_p,POINTER(c_int),POINTER(c_int),c_int,c_int,c_int,c_bool,POINTER(c_double),POINTER(c_double),POINTER(c_double)] 


self.polynomialFittingDLL.loadComputationFromPython(self.dll,
                              self.btuplesDllFlat.ctypes.data_as(POINTER(c_int)),
                              self.bterm.ctypes.data_as(POINTER(c_int)),
                              len(self.bterm),
                              sum(self.bterm),
                              len(self.rangeX),
                              baseType,
                              self.coefficients.ctypes.data_as(POINTER(c_double)),
                              self.rangeX.ctypes.data_as(POINTER(c_double)),
                              self.minX.ctypes.data_as(POINTER(c_double)))

C++ 方面:

#ifdef _MSC_VER
    typedef __int64 int64_t;
#else
    #include <stdint.h>
#endif

DLL_EXPORT void loadComputationFromPython(PolynomialCurve* curve,__int64 *_btuple,
                     int *_bterm, int _btermSize,
                     int _Nvalidbtuple,int _Nparams,bool _polynomial,
                     double *_coefficients,
                     double *_rangeX,double *_minX) 
{
curve->loadComputationFromPython(_btuple,_bterm,_btermSize,_Nvalidbtuple,_Nparams,_polynomial,_coefficients,_rangeX,_minX);
}

void PolynomialCurve::loadComputationFromPython(__int64 *_btuple,
                     int *_bterm, int _btermSize,
                     int _Nvalidbtuple,int _Nparams,bool _polynomial,
                     double *_coefficients,
                     double *_rangeX,double *_minX) 
{
btermSize = _btermSize;
Nparams = _Nparams;
btuple = new int*[btermSize];
for (int i=0;i<btermSize;++i) {
    btuple[i] = new int[Nparams];
    for (int j=0;j<Nparams;++j) {
        btuple[i][j] = _btuple[i*Nparams+j];
    }
}
bterm = _bterm;
NvalidBtuple = _Nvalidbtuple;
polynomial = _polynomial;
coefficients = _coefficients;
rangeX = _rangeX;
minX = _minX;
}

我必须使用 __int64 类型才能为_btuple 提供正确的整数类型。但是其他 int 指针似乎仍然无法处理整数大小...

我的问题是如何在 c++ 代码中保持一致以使所有 int 属性始终具有相同的位大小?我希望哪个大小与 python 中的 c_int 大小保持一致。 __int64 类型是否足以解决我的问题?我可以定义 __int64 的指针吗?我应该对双打同样小心吗?

当我从 32 位编译更改为 64 位时,出现了这些问题。 谢谢

编辑: 进一步观察到的是:

从 python 到 c++:python 整数是 64 字节整数,我必须在 C++ 中指定接收的整数是 64 字节(使用 __int64 类型)

从 C++ 到 python:C++ 中的 int 类型是一个 32 字节的整数,当我在 python 中接收整数时,我必须用 c_int32 类型指定它的大小:

addrBtuples = self.polynomialFittingDLL.getBtuples(self.dll)
self.btuplesDllFlat = np.ctypeslib.as_array((c_int32 * self.btuplesSize).from_address(addrBtuples))

所以,为了尽可能地便携:我应该将 python int“转换”为 32 字节吗?还是我应该强制 c++ 库使用 __int64 类型?

【问题讨论】:

    标签: python c++ int ctypes


    【解决方案1】:

    我不确定我是否理解你的问题,但你不应该用c_int64“遮蔽”c_intc_int 类型在 64 位上仍然是 4 个字节

    >>> import platform
    >>> platform.architecture()
    ('64bit', 'WindowsPE')
    >>> import ctypes
    >>> ctypes.sizeof(ctypes.c_int)
    4
    

    第二个参数应该是POINTER(ctypes.c_int64):

    # c_int = c_int64
    polynomialFittingDLL.loadComputationFromPython.restype = None
    polynomialFittingDLL.loadComputationFromPython.argtypes = [c_void_p,POINTER(ctypes.c_int64),POINTER(c_int),c_int,c_int,c_int,c_bool,POINTER(c_double),POINTER(c_double),POINTER(c_double)] 
    

    此外,无论指针指向什么类型,指针都保持相同的大小。

    【讨论】:

    • 我明白你的意思。这个技巧只是为了让我在测试阶段快速从一种类型转换到另一种类型。谢谢
    【解决方案2】:

    C 端的 int 和 double 的大小取决于实现(标准仅指定最小大小)。因此,它可能取决于编译器。尽管如此,在大多数情况下,ctypes python 库的功能与 C++ 编译器在同一平台上的功能是一致的。

    因此,要解决此问题,您需要以连贯的方式从 python 端更改大小以获得正确的转换。 鉴于您的情况下的 C 函数签名,我认为 python 端的以下签名可以工作(仅将第一个更改为 c_longlong):

    polynomialFittingDLL.loadComputationFromPython.argtypes = [c_void_p,
                    POINTER(c_longlong),
                    POINTER(c_int),
                    c_int,c_int,c_int,c_bool,
                    POINTER(c_double),
                    POINTER(c_double),POINTER(c_double)]
    

    但是,如果您的 C++ 编译器正在增加整数的大小,您应该尝试:

    polynomialFittingDLL.loadComputationFromPython.argtypes = [c_void_p,
                    POINTER(c_longlong),
                    POINTER(c_long),
                    c_long,c_long,c_long,c_bool,
                    POINTER(c_double),
                    POINTER(c_double),POINTER(c_double)]
    

    如果双打也增加了:

    polynomialFittingDLL.loadComputationFromPython.argtypes = [c_void_p,
                    POINTER(c_longlong),
                    POINTER(c_long),
                    c_long,c_long,c_long,c_bool,
                    POINTER(c_longdouble),
                    POINTER(c_longdouble),POINTER(c_longdouble)]
    

    有关所有 ctypes 数据类型的更多信息,请参阅 https://docs.python.org/2/library/ctypes.html

    关键是您需要检查哪个是适合 ctypes 和编译模块之间的转换。

    我建议测试边界情况(长整数和整数最大和最小大小,以及溢出),以查看一切是否正常。

    【讨论】:

    • 如果我理解正确你的观点,那么 c 库在所有不同的计算机上的行为总是相同的。因此必须控制 python 端以适应 C 库的要求?
    • 我在 c++ 库中将 __int64 替换为 int,并强制所有 int 指针为 c_long 类型。这行得通。非常感谢
    • @Yvus,退出对面。据我了解,只要编译器满足标准的最小尺寸,它就可以扩充它们。在同一个平台上,通常编译器的行为是相同的,但这并不确定。如果您使用与用于编译 CPython 的编译器不同的编译器编译模块,则会出现转换未正确完成的变化。但这只是一个猜测,这从未发生在我身上。但显然在这种情况下正在发生什么,因为来自 python 端的 long 与模块端的整数具有相同的大小。
    猜你喜欢
    • 2012-09-08
    • 2014-07-15
    • 1970-01-01
    • 1970-01-01
    • 2018-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-27
    相关资源
    最近更新 更多