Python ctypes:如何使用传递给 DLL 的指针?
Python ctypes: how to use pointer passed to DLL?
使用 ctypes,我在 Python 中创建了一个数组以传递给 ctypes.WinDLL:
arrA = (ctypes.c_float * len(varA))(*varA)
然后我将指向数组的指针传递给 DLL:
retvar = SimpleTest(ctypes.byref(pvarr),ctypes.byref(pvarr2))
其中 pvarr 的第一个元素是指向数组 arrA 的指针。
但是当我尝试将值写入数组 arrA(使用传递的指针)时,我得到 "invalid access to memory location."
所以我的问题是:我现在如何使用指向在 Python 中创建并传递给 DLL 的 ctypes.c_float 数组的指针?这不可能吗?
经过一段时间的努力,我已经细化了这个问题。上面显示的数组是不可变的;要传递一个可变数组,我们这样做:
OutputArrayType = ctypes.c_float * 1000
arrNew = OutputArrayType()
ctypes 数组类型是 class,因此要使用它我们必须创建一个 class 实例 (arrayNew)。
但是当我通过引用传递它的指针时:
retvar = SimpleTest(ctypes.byref(PVarrNew),ctypes.byref(arrNew))
指针值与 id(arrayNew) 不同。即便如此,DLL 仍然无法访问任一指针中的任何值,因为我得到 "invalid access to memory."
所以我现在的问题是:为什么 ctypes.byref(arrNew) 传递的指针与 id(arrNew) 不同。
马克,谢谢你的回复。以下是简明摘要:
第一个数组不是可变的,每次赋值都会创建一个新对象;我通过在赋值前后检查它的 id() 来确认这一点。但是,实例化为 class 的第二个数组是可变的,所以这就是我使用它的原因。
所以我创建了数组:
OutputArrayType = ctypes.c_int64 * 1000
arrNew = OutputArrayType()
并调用 DLL:
retvar = SimpleTest(ctypes.byref(PVarrNew),ctypes.byref(arrNew))
在64位汇编器中,第二个参数(指向arrNew的指针)传入rdx。所以在 NASM 中,我可以用两种不同的方式写入这个数组,但是 return "invalid access to memory location."
mov rdi,rdx
mov rax,1534
mov [rdi+8],rax
push qword [rax]
pop qword [rdx+32]
如果我在对 DLL 的调用中颠倒数组的顺序(指向数组的指针在 rcx 中),也会发生同样的情况。
但是,我可以从数组中读取,但不能写入。
非常感谢您的帮助。
你的两个例子都是可变的。您提到了一个 assignment,它总是创建一个新对象但没有示例...:^) 这就是我所说的可重现示例的意思。使用适当的 Python:
编译 32 位或 64 位作品
test.c(Windows Microsoft 编译器示例)
#include <stdio.h>
__declspec(dllexport) void __stdcall SimpleTest(float* array, int length)
{
int i;
for(i = 0; i < length; ++i)
{
printf("array[%d] = %f\n",i,array[i]);
array[i] *= 2;
}
}
test.py(在 Python 2 和 3 之间可移植)
from __future__ import print_function
from ctypes import *
varA = [1.2,2.5,3.5]
arr = (c_float * len(varA))(*varA) # 1st example
print(id(arr))
arr[0] = 1.5 # mutate array
print(id(arr))
arrType = c_float * 10 # 2nd example
arrInstance = arrType()
print(id(arrInstance))
arrInstance[0] = 1.5 # mutate array
print(id(arrInstance))
dll = WinDLL('test')
print(list(arr))
dll.SimpleTest(arr,len(arr)) # Passing the array to C and changing it
print(list(arr))
输出(32和64相同,只是ID不同,注意突变后ID不会改变)
2610964912456
2610964912456
2610964912968
2610964912968
[1.5, 2.5, 3.5]
array[0] = 1.500000
array[1] = 2.500000
array[2] = 3.500000
[3.0, 5.0, 7.0]
使用 ctypes,我在 Python 中创建了一个数组以传递给 ctypes.WinDLL:
arrA = (ctypes.c_float * len(varA))(*varA)
然后我将指向数组的指针传递给 DLL:
retvar = SimpleTest(ctypes.byref(pvarr),ctypes.byref(pvarr2))
其中 pvarr 的第一个元素是指向数组 arrA 的指针。
但是当我尝试将值写入数组 arrA(使用传递的指针)时,我得到 "invalid access to memory location."
所以我的问题是:我现在如何使用指向在 Python 中创建并传递给 DLL 的 ctypes.c_float 数组的指针?这不可能吗?
经过一段时间的努力,我已经细化了这个问题。上面显示的数组是不可变的;要传递一个可变数组,我们这样做:
OutputArrayType = ctypes.c_float * 1000
arrNew = OutputArrayType()
ctypes 数组类型是 class,因此要使用它我们必须创建一个 class 实例 (arrayNew)。
但是当我通过引用传递它的指针时:
retvar = SimpleTest(ctypes.byref(PVarrNew),ctypes.byref(arrNew))
指针值与 id(arrayNew) 不同。即便如此,DLL 仍然无法访问任一指针中的任何值,因为我得到 "invalid access to memory."
所以我现在的问题是:为什么 ctypes.byref(arrNew) 传递的指针与 id(arrNew) 不同。
马克,谢谢你的回复。以下是简明摘要:
第一个数组不是可变的,每次赋值都会创建一个新对象;我通过在赋值前后检查它的 id() 来确认这一点。但是,实例化为 class 的第二个数组是可变的,所以这就是我使用它的原因。
所以我创建了数组:
OutputArrayType = ctypes.c_int64 * 1000
arrNew = OutputArrayType()
并调用 DLL:
retvar = SimpleTest(ctypes.byref(PVarrNew),ctypes.byref(arrNew))
在64位汇编器中,第二个参数(指向arrNew的指针)传入rdx。所以在 NASM 中,我可以用两种不同的方式写入这个数组,但是 return "invalid access to memory location."
mov rdi,rdx
mov rax,1534
mov [rdi+8],rax
push qword [rax]
pop qword [rdx+32]
如果我在对 DLL 的调用中颠倒数组的顺序(指向数组的指针在 rcx 中),也会发生同样的情况。
但是,我可以从数组中读取,但不能写入。
非常感谢您的帮助。
你的两个例子都是可变的。您提到了一个 assignment,它总是创建一个新对象但没有示例...:^) 这就是我所说的可重现示例的意思。使用适当的 Python:
编译 32 位或 64 位作品test.c(Windows Microsoft 编译器示例)
#include <stdio.h>
__declspec(dllexport) void __stdcall SimpleTest(float* array, int length)
{
int i;
for(i = 0; i < length; ++i)
{
printf("array[%d] = %f\n",i,array[i]);
array[i] *= 2;
}
}
test.py(在 Python 2 和 3 之间可移植)
from __future__ import print_function
from ctypes import *
varA = [1.2,2.5,3.5]
arr = (c_float * len(varA))(*varA) # 1st example
print(id(arr))
arr[0] = 1.5 # mutate array
print(id(arr))
arrType = c_float * 10 # 2nd example
arrInstance = arrType()
print(id(arrInstance))
arrInstance[0] = 1.5 # mutate array
print(id(arrInstance))
dll = WinDLL('test')
print(list(arr))
dll.SimpleTest(arr,len(arr)) # Passing the array to C and changing it
print(list(arr))
输出(32和64相同,只是ID不同,注意突变后ID不会改变)
2610964912456
2610964912456
2610964912968
2610964912968
[1.5, 2.5, 3.5]
array[0] = 1.500000
array[1] = 2.500000
array[2] = 3.500000
[3.0, 5.0, 7.0]