Python将32位指针地址传递给C函数 [英] Python is passing 32bit pointer address to C functions
问题描述
我想在Python脚本中的共享库中调用我的C函数。传递指针时出现问题,64位地址似乎在被调用函数中被截断为32位地址。 Python和我的库都是64位的。
下面的示例代码演示了这个问题。 Python脚本打印传递给C函数的数据的地址。然后,从被调用的C函数内打印接收的地址。此外,C函数通过打印本地创建内存的大小和地址证明它是64位。如果指针以任何其他方式使用,则结果为segfault。
CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
add_library(plate MODULE plate.c)
plate.c
#include< stdio .h>
#include< stdlib.h>
void plate(float * in,float * out,int cnt)
{
void * ptr = malloc(1024);
fprintf(stderr,passed address:%p \\\
,in);
fprintf(stderr,local pointer size:%lu\\\
local pointer address:%p\\\
,sizeof(void *),ptr);
free(ptr);
}
test_plate.py
$ b
import numpy
import scipy
import ctypes
N = 3
x = numpy。 (N,dtype = numpy.float32)
y = numpy.ones(N,dtype = numpy.float32)
plate = ctypes.cdll.LoadLibrary('libplate.so')
print'传递地址:%0x'%x.ctypes.data
plate.plate(x.ctypes.data,y.ctypes.data,ctypes.c_int(N))
从python-2.7输出
在[1]:run ../ test_plate.py
传递地址:7f9a09b02320
传递的地址:0x9b02320
本地指针大小:8
本地指针地址:0x7f9a0949a400
解决方案问题是 ctypes
模块不检查您要调用的函数的函数签名。相反,它基于Python类型的C类型,所以行...
plate.plate(x.ctypes。 data,y.ctypes.data,ctypes.c_int(N))
...传递前两个参数作为整数。
为了避免被截断,您需要告诉 ctypes
那些参数实际上是像...的指针。
plate.plate(ctypes.c_void_p(x.ctypes.data),
ctypes.c_void_p(y.ctypes.data),
ctypes.c_int(N))
...虽然它们实际上是指向的指针是另一回事 - 它们可能不是指针 float
。
/ strong>
已经为 numpy
在这个问题的具体例子,但我会离开这里,因为它可能在一般情况下的指针截断程序员使用 numpy
。 p>
I would like to call my C functions within a shared library from Python scripts. Problem arrises when passing pointers, the 64bit addresses seem to be truncated to 32bit addresses within the called function. Both Python and my library are 64bit.
The example codes below demonstrate the problem. The Python script prints the address of the data being passed to the C function. Then, the address received is printed from within the called C function. Additionally, the C function proves that it is 64bit by printing the size and address of locally creating memory. If the pointer is used in any other way, the result is a segfault.
CMakeLists.txt
cmake_minimum_required (VERSION 2.6)
add_library(plate MODULE plate.c)
plate.c
#include <stdio.h>
#include <stdlib.h>
void plate(float *in, float *out, int cnt)
{
void *ptr = malloc(1024);
fprintf(stderr, "passed address: %p\n", in);
fprintf(stderr, "local pointer size: %lu\n local pointer address: %p\n", sizeof(void *), ptr);
free(ptr);
}
test_plate.py
import numpy
import scipy
import ctypes
N = 3
x = numpy.ones(N, dtype=numpy.float32)
y = numpy.ones(N, dtype=numpy.float32)
plate = ctypes.cdll.LoadLibrary('libplate.so')
print 'passing address: %0x' % x.ctypes.data
plate.plate(x.ctypes.data, y.ctypes.data, ctypes.c_int(N))
Output from python-2.7
In [1]: run ../test_plate.py
passing address: 7f9a09b02320
passed address: 0x9b02320
local pointer size: 8
local pointer address: 0x7f9a0949a400
解决方案 The problem is that the ctypes
module doesn't check the function signature of the function you're trying to call. Instead, it bases the C types on the Python types, so the line...
plate.plate(x.ctypes.data, y.ctypes.data, ctypes.c_int(N))
...is passing the the first two params as integers. See eryksun's answer for the reason why they're being truncated to 32 bits.
To avoid the truncation, you'll need to tell ctypes
that those params are actually pointers with something like...
plate.plate(ctypes.c_void_p(x.ctypes.data),
ctypes.c_void_p(y.ctypes.data),
ctypes.c_int(N))
...although what they're actually pointers to is another matter - they may not be pointers to float
as your C code assumes.
Update
eryksun has since posted a much more complete answer for the numpy
-specific example in this question, but I'll leave this here, since it might be useful in the general case of pointer truncation for programmers using something other than numpy
.
这篇关于Python将32位指针地址传递给C函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!