Python将32位指针地址传递给C函数 [英] Python is passing 32bit pointer address to C functions

查看:258
本文介绍了Python将32位指针地址传递给C函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆