当从";返回空指针时会发生什么;“国外职能”;在python中使用ctypes?

当从";返回空指针时会发生什么;“国外职能”;在python中使用ctypes?,python,c,ctypes,Python,C,Ctypes,用ctypes包装C函数时,如果方法返回一个空指针,指向映射到从ctypes.Structure派生的python类的结构,会发生什么情况?另外,当传递给方法的有效指针设置为空值时会发生什么情况?以下测试将帮助我们发现: //python_ctypes_test.c #include <stdlib.h> struct test_struct { int a; int b; int c; int d; } typedef test_struct;

用ctypes包装C函数时,如果方法返回一个空指针,指向映射到从ctypes.Structure派生的python类的结构,会发生什么情况?另外,当传递给方法的有效指针设置为空值时会发生什么情况?以下测试将帮助我们发现:

//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;
    }
}

事实证明,开发人员不必关心指针的地址,指针已经传递给函数,并且正在更改

print py_get_two_floats(True)
  (1.100000023841858, 2.200000047683716)

print py_get_two_floats(False)
  (0.0, 0.0)
在第二种情况下,值从其初始化状态保持不变。这通常是正确的。已将
float1_值
float2_值
初始化为10和20。这些价值也将保持不变

正如@eryksun指出的那样:

float1和float2是包含 两辆彩车。您可以将该值设置为0或任何其他地址,但 这只是改变了一个局部变量。那和我的不一样 取消引用指针(例如*float1)以访问浮点 在地址处的值

在返回值的情况下,处理方式不同。返回的对象的计算结果为true(非null)或false(null)

尝试访问空指针会导致ValueError异常

print py_get_test_struct(True)
  ((1, 2), (3, 4))

print py_get_test_struct(False)
Traceback (most recent call last):
  File "python_ctypes.py", line 52, in <module>
    print py_get_test_struct(False)
  File "python_ctypes.py", line 24, in py_get_test_struct
    return dll.get_test_struct(valid).contents.unwrap()
ValueError: NULL pointer access
print py\u get\u test\u struct(True)
((1, 2), (3, 4))
打印py\u get\u test\u结构(False)
回溯(最近一次呼叫最后一次):
文件“python_ctypes.py”,第52行,在
打印py\u get\u test\u结构(False)
py\u get\u test\u结构中的第24行文件“python\u ctypes.py”
返回dll.get\u test\u struct(有效).contents.unwrap()
ValueError:空指针访问

这应该是基础C编程的一课吗?(1)
float1
get\u two\u float
中的一个局部变量,因此将其设置为0当然对调用方的上下文没有影响。(2) 至于访问
NULL
指针,您可以简单地使用
ctypes.pointer(_test_struct)().contents
来演示
ValueError
。我之所以分享这个示例,是因为我正在调试使用pyGLFW(GLFW C库的包装器)的代码。在我演示的两种情况下,如果C代码返回null,python将返回什么。因为我找不到一个好的例子来回答这个问题,所以我决定发布它。
float1
float2
是包含两个浮点地址的局部变量。您可以将该值设置为0或任何其他地址,但这只是更改一个局部变量。这与取消引用指针(例如,
*float1
)以访问地址处的浮点值不同。谢谢,我现在看到了我的错误。您是正确的,
float1
float2
在C调用后永远不会为空。我误读了我正在测试的API。我将修改我的答案以反映这一点。下载源代码:你认为这个问题缺少什么吗?它讨论了它们的布尔值并演示了
ValueError
。我想我想看一节讨论ctypes如何处理从C函数返回的空指针以及通过引用传递的指针,这些指针被C函数更改为空指针。我不清楚这些问题是直接解决的。它确实讨论了
NULL
指针;它们是如何产生的并不重要。C函数在寄存器中返回一个整数值(例如x64中的rax),ctypes根据该值创建一个指针实例,该值可以是0。对于第二个问题,您不是通过引用传递指针。您通过值传递它们。通常,您只需使用
float1=ctypes.c_float()
并将引用作为
ctypes.byref(float1)
传递,而不是创建指针实例。这是传递对浮点值的引用,但地址本身是按值传递的,在堆栈上或在寄存器中(例如,x64中的寄存器
rcx
)。
print py_get_test_struct_safe(True)
  ((1, 2), (3, 4))

print py_get_test_struct_safe(False)
  None
print py_get_test_struct(True)
  ((1, 2), (3, 4))

print py_get_test_struct(False)
Traceback (most recent call last):
  File "python_ctypes.py", line 52, in <module>
    print py_get_test_struct(False)
  File "python_ctypes.py", line 24, in py_get_test_struct
    return dll.get_test_struct(valid).contents.unwrap()
ValueError: NULL pointer access