如何将指向 Python cffi 结构的指针转换为 System.IntPtr (.NET)?
How to cast a pointer to a Python cffi struct to System.IntPtr (.NET)?
我需要将 System.IntPtr 传递给 .NET 函数(Python with pythonnet)。此指针应引用在 cffi 中创建的结构。
我找到了 this:
from CLR.System import IntPtr, Int32
i = Int32(32)
p = IntPtr.op_Explicit(i)
这是我目前尝试的方法
import clr
from cffi import FFI
ffi = FFI()
custom_t = '''
typedef struct
{
float x;
float y;
float z;
} float3;
'''
ffi.cdef(custom_t)
cfloat3 = ffi.new("float3 *")
cfloat3.x = 1.0
cfloat3.y = 2.0
cfloat3.z = 3.0
print(cfloat3)
from System import IntPtr
p = IntPtr.op_Explicit(id(cfloat3)) #works, sort of...
print(p)
#I would rather see something like
p2 = IntPtr.op_Explicit(ffi.addressof(cfloat3).value)
p3 = IntPtr(ffi.cast("float3*", cfloat3))
p4 = IntPtr(ffi.cast("void3*", cfloat3))
#type(_), ffi.typeof(_), ffi.typeof(_).kind, ffi.addressof()
但我不确定使用 IntPtr.op_Explicit 是否是最佳解决方案。它看起来有点像与 id()
结合使用的解决方法,我很确定有更好的解决方案。
FFI 内置了 addressof 函数:
Python.Net 内部不直接支持 CFFI,反之亦然,因此您需要将指针从一个库转换为一个整数,然后将该整数重新导入另一个库。
来自 CFFI,intaddr = ffi.cast("intptr_t", p)
会给你一个整数。那么你可能可以做 IntPtr(intaddr)
.
解决方法是使用IntPtr
的Overloads
方法
from System import IntPtr, Int32, Int64
my_ptr = ffi.cast("intptr_t", my_c_struct)
cs_handle = IntPtr.Overloads[Int64](Int64(int(my_ptr)))
如前所述 and here。
这是一个工作示例:
import clr
from cffi import FFI
ffi = FFI()
custom_t = '''
typedef struct
{
float x;
float y;
float z;
} float3;
'''
ffi.cdef(custom_t)
cfloat3 = ffi.new("float3 *")
cfloat3.x = 1.0
cfloat3.y = 2.0
cfloat3.z = 3.0
print(cfloat3)
from System import IntPtr, Int32, Int64
my_ptr = ffi.cast("intptr_t", cfloat3)
print(my_ptr)
print(ffi.typeof(my_ptr))
print(ffi.typeof(my_ptr).kind)
print(ffi.typeof(my_ptr).cname)
print(int(my_ptr))
print('hex', hex(int(my_ptr)))
#you don't need to cast to System.Int64 first, also works without:
#with casting the Python int to System.Int64
cs_handle = IntPtr.Overloads[Int64](int(my_ptr))
print(cs_handle)
#without casting the Python int to System.Int64
cs_handle = IntPtr.Overloads[Int64](Int64(int(my_ptr)))
print(cs_handle)
# using this workaround mentioned in the question also works
p = IntPtr.op_Explicit(int(my_ptr)) #works, sort of...
print('op_Explicit', p)
#careful: do not use the id() of the C structure, it is different and incorrect
print(cfloat3)
print(ffi.addressof(cfloat3[0]))
print('id(cfloat3)', id(cfloat3), hex(id(cfloat3)))
关于上面发生的事情的一些进一步信息(在这里和那里找到):
C#'s IntPtr maps exactly to C/C++'s intptr_t.
intptr_t integer type capable of holding a pointer
To cast a pointer to an int, cast it to intptr_t or uintptr_t, which are defined by C to be large enough integer types. cffi doc with examples
IntPtr is just a .NET type for void*.
The equivalent of an unmanaged pointer in the C# language is IntPtr. You can freely convert a pointer back and forth with a cast. No pointer type is
associated with it even though its name sounds like "pointer to int",
it is the equivalent of void* in C/C++.
IntPtr(5) complains that int/long' value cannot be converted to System.IntPtr
. It seems like it is trying to cast or something instead of calling the constructor. (found here)
Methods of CLR objects have an '_ overloads _', which will soon be deprecated in favor of iPy compatible Overloads, attribute that can be used for this purpose. (found here)
我需要将 System.IntPtr 传递给 .NET 函数(Python with pythonnet)。此指针应引用在 cffi 中创建的结构。
我找到了 this:
from CLR.System import IntPtr, Int32
i = Int32(32)
p = IntPtr.op_Explicit(i)
这是我目前尝试的方法
import clr
from cffi import FFI
ffi = FFI()
custom_t = '''
typedef struct
{
float x;
float y;
float z;
} float3;
'''
ffi.cdef(custom_t)
cfloat3 = ffi.new("float3 *")
cfloat3.x = 1.0
cfloat3.y = 2.0
cfloat3.z = 3.0
print(cfloat3)
from System import IntPtr
p = IntPtr.op_Explicit(id(cfloat3)) #works, sort of...
print(p)
#I would rather see something like
p2 = IntPtr.op_Explicit(ffi.addressof(cfloat3).value)
p3 = IntPtr(ffi.cast("float3*", cfloat3))
p4 = IntPtr(ffi.cast("void3*", cfloat3))
#type(_), ffi.typeof(_), ffi.typeof(_).kind, ffi.addressof()
但我不确定使用 IntPtr.op_Explicit 是否是最佳解决方案。它看起来有点像与 id()
结合使用的解决方法,我很确定有更好的解决方案。
FFI 内置了 addressof 函数:
Python.Net 内部不直接支持 CFFI,反之亦然,因此您需要将指针从一个库转换为一个整数,然后将该整数重新导入另一个库。
来自 CFFI,intaddr = ffi.cast("intptr_t", p)
会给你一个整数。那么你可能可以做 IntPtr(intaddr)
.
解决方法是使用IntPtr
Overloads
方法
from System import IntPtr, Int32, Int64
my_ptr = ffi.cast("intptr_t", my_c_struct)
cs_handle = IntPtr.Overloads[Int64](Int64(int(my_ptr)))
如前所述
这是一个工作示例:
import clr
from cffi import FFI
ffi = FFI()
custom_t = '''
typedef struct
{
float x;
float y;
float z;
} float3;
'''
ffi.cdef(custom_t)
cfloat3 = ffi.new("float3 *")
cfloat3.x = 1.0
cfloat3.y = 2.0
cfloat3.z = 3.0
print(cfloat3)
from System import IntPtr, Int32, Int64
my_ptr = ffi.cast("intptr_t", cfloat3)
print(my_ptr)
print(ffi.typeof(my_ptr))
print(ffi.typeof(my_ptr).kind)
print(ffi.typeof(my_ptr).cname)
print(int(my_ptr))
print('hex', hex(int(my_ptr)))
#you don't need to cast to System.Int64 first, also works without:
#with casting the Python int to System.Int64
cs_handle = IntPtr.Overloads[Int64](int(my_ptr))
print(cs_handle)
#without casting the Python int to System.Int64
cs_handle = IntPtr.Overloads[Int64](Int64(int(my_ptr)))
print(cs_handle)
# using this workaround mentioned in the question also works
p = IntPtr.op_Explicit(int(my_ptr)) #works, sort of...
print('op_Explicit', p)
#careful: do not use the id() of the C structure, it is different and incorrect
print(cfloat3)
print(ffi.addressof(cfloat3[0]))
print('id(cfloat3)', id(cfloat3), hex(id(cfloat3)))
关于上面发生的事情的一些进一步信息(在这里和那里找到):
C#'s IntPtr maps exactly to C/C++'s intptr_t.
intptr_t integer type capable of holding a pointer
To cast a pointer to an int, cast it to intptr_t or uintptr_t, which are defined by C to be large enough integer types. cffi doc with examples
IntPtr is just a .NET type for void*.
The equivalent of an unmanaged pointer in the C# language is IntPtr. You can freely convert a pointer back and forth with a cast. No pointer type is associated with it even though its name sounds like "pointer to int", it is the equivalent of void* in C/C++.
IntPtr(5) complains that
int/long' value cannot be converted to System.IntPtr
. It seems like it is trying to cast or something instead of calling the constructor. (found here)Methods of CLR objects have an '_ overloads _', which will soon be deprecated in favor of iPy compatible Overloads, attribute that can be used for this purpose. (found here)