Python如何向C指针传递数据

在之前的文章Python调用C/C++动态链接库中,举例说明了Python访问C指针所指向数据的方式,主要是从指针所指向的内存中取数据。今天遇到的问题是,如何将Python产生的数组赋值给C指针。

下面用一个小例子来说明一下。

C从外部获取指针所指向的数据,并通过print_array()函数打印出来,C代码:

#include "stdio.h"
#include <iostream>

extern "C"
{

using namespace std;

// 创建一个长度为len的int型指针
int *get_pointer(int len)
{
	int *ptr = new int[len];
	return ptr;
}

// 打印指针数据,len为打印的int型数据的长度
void print_array(int *array_in, int len)
{	
	for(int i = 0; i < len; i++)
	{
		printf("array_in[%d] = %d \n", i, array_in[i]);
	}
}

// 释放指针
void free_pointer(int *ptr)
{
	if(ptr)
	{
		delete [] ptr;
	}
}


}	  

编译C动态库:

g++ -std=c++11 python2c.cpp -o libpy2c.so -shared -fPIC

注意,不要加-c选项,否则编译出来的动态库加载时会报错:

only ET_DYN and ET_EXEC can be loaded

C动态库有了,接下来通过Python产生数据,并传递给C指针。传递数据的方式目前试用了两种,都能work。

1. 方法1,逐元素拷贝

# -*- coding: utf-8 -*-
from ctypes import *
import numpy as np

lib_path = r'./libpy2c.so'
solib = cdll.LoadLibrary(lib_path)

# Create C pointer
c_len = 10
solib.get_pointer.argtypes = [c_int]
solib.get_pointer.restype = POINTER(c_int)
ptr = solib.get_pointer(c_len)

print("ptr = {}".format(ptr))


# Create a python array
py_len = 10
py_array = [i for i in range(py_len)]
py_array = np.array(py_array).astype(np.int32)
for i in range(py_len):
	print(py_array[i])

# Method 1
# 方法1,逐个元素拷贝,将Python数组逐个拷贝到ctypes pointer所指向的内存中。
for i in range(py_len):
	ptr[i] = py_array[i]

'''	
# Method 2
# 方法2,通过cast方法将Python数组数据转换成指针形式。
py_array = np.ascontiguousarray(py_array, dtype=np.int32)
ptr = cast(py_array.ctypes.data, POINTER(c_int))
print("ptr = {}".format(ptr))
'''

# Call C shared library to print pointer
solib.print_array.argstype = [POINTER(c_int), c_int]
solib.print_array.restype = c_void_p
solib.print_array(ptr, py_len)

solib.free_pointer.argstype = [POINTER(c_int)]
solib.free_pointer.restype = c_void_p
solib.free_pointer(ptr)

执行结果:

从以上结果中可以看到,数据成功地从Python数组传递给了C指针。

2. 方法2,通过cast方式将数组转换成ctypes指针

将Python代码中的方法1关闭,方法2打开:

执行结果与第一种方法一致,都能成功将Python的数组数据传递给C语言的指针。 

3. 指针越界测试

如果在Python中创建的数组大小大于C语言为指针分配的内存大小,情况如何呢?在Python代码中,我们保持c_len=10不变,将py_len改为20,测试两种方法。

为了截图方便,我们把Python中的数组打印关闭。 

方法1结果:

虽然完成了数据传递,但是出现了内存越界。

我们再来看方法2:

 

完成了数据传递,而且一切正常,从图上cast前后ptr值的变化来看,指针变量ptr实际上是指向了一个新的地址,也就是通过cast转换而得到的数据的地址。因此,这时不会再向原指针地址写数据,也就不会受原指针内存空间的限制。

但以上代码这样写是有问题的,因为通过C开辟出来的空间是无法被释放的,因为最后传入free_pointer()的地址变化了。所以如果使用cast方式,由于是通过Python来创建指针,因此C库中的get_pointer()函数就无需调用了。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值