【发布时间】:2015-04-15 05:29:40
【问题描述】:
当使用 ctypes 包装 C 函数时,当方法返回指向映射到从 ctypes.Structure 派生的 python 类的结构的 NULL 指针时会发生什么?此外,当传递给方法的有效指针设置为 NULL 值时会发生什么?以下测试将帮助我们找出答案:
//python_ctypes_test.c
#include <stdlib.h>
struct test_struct {
int a;
int b;
int c;
int d;
} typedef test_struct;
test_struct* get_test_struct(const int valid) {
test_struct* newStruct = 0;
if (valid > 0) {
newStruct = malloc(sizeof *newStruct);
newStruct->a = 1;
newStruct->b = 2;
newStruct->c = 3;
newStruct->d = 4;
}
return newStruct;
}
void get_two_floats(const int valid, float* float1, float* float2) {
if (valid > 0) {
*float1 = 1.1f;
*float2 = 2.2f;
} else {
float1 = 0;
float2 = 0;
}
}
#python_ctypes_test.py
import ctypes
import ctypes.util
dll = ctypes.CDLL('libpython_ctypes_test.so')
class _test_struct(ctypes.Structure):
_fields_ = [("a", ctypes.c_int),
("b", ctypes.c_int),
("c", ctypes.c_int),
("d", ctypes.c_int)]
def wrap(self, something):
self.a,self.b,self.c,self.d = something
def unwrap(self):
part1 = self.a,self.b
part2 = self.c,self.d
return part1, part2
dll.get_test_struct.restype = ctypes.POINTER(_test_struct)
dll.get_test_struct.argtypes = [ctypes.c_int]
def py_get_test_struct(valid):
return dll.get_test_struct(valid).contents.unwrap()
def py_get_test_struct_safe(valid):
testStructPtr = dll.get_test_struct(valid)
if testStructPtr:
return testStructPtr.contents.unwrap()
else:
return None
dll.get_two_floats.restype = None
dll.get_two_floats.argtypes = [ctypes.c_int,
ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float)]
def py_get_two_floats(valid):
float1_value = ctypes.c_float(0)
float1 = ctypes.pointer(float1_value)
float2_value = ctypes.c_float(0)
float2 = ctypes.pointer(float2_value)
dll.get_two_floats(valid, float1, float2)
return float1_value.value, float2_value.value
print py_get_two_floats(True)
print py_get_two_floats(False)
print py_get_test_struct_safe(True)
print py_get_test_struct_safe(False)
print py_get_test_struct(True)
print py_get_test_struct(False)
【问题讨论】:
-
您认为ctypes pointers tutorial 中缺少什么吗?它讨论了它们的布尔值并演示了
ValueError。 -
我想我想看一节讨论 ctypes 如何处理从 C 函数返回的 NULL 指针和由 C 函数更改为 NULL 指针的引用传递的指针。我不清楚这些点是直接解决的。
-
它确实讨论了
NULL指针;它们是如何创建的并不重要。 C 函数在寄存器中返回一个整数值(例如 x64 中的rax),并且 ctypes 从该值创建一个指针实例,该值可能为 0。对于第二个问题,您没有通过引用传递指针。您正在按值传递它们。 -
通常您只需使用
float1 = ctypes.c_float()并将引用作为ctypes.byref(float1)传递,而不是创建指针实例。这是传递对浮点值的引用,但地址本身是按值传递的,无论是在堆栈上还是在寄存器中(例如,x64 中的寄存器rcx)。