从库返回的 ctypes 结构

tot*_*ter 7 c python ctypes wrapper python-2.7

给定一个简单的 C 文件:

#include <stdio.h>

typedef struct point {
    int x;
    int y;
} POINT; 

POINT get_point() 
{
    POINT p = {1, 2};
    return p;
}
Run Code Online (Sandbox Code Playgroud)

我有一个简单的 python 文件:

from ctypes import *
import os

lib_name = '/testlib.so' 
test_lib = CDLL(os.getcwd() + lib_name)

class POINT(Structure):
    _fields_ = [('x', c_int),
                ('y', c_int)]

# Sets p1 to the integer 1
p1 = test_lib.get_point()
# Sets p2 to the struct POINT with values {1, 0}
p2 = POINT(test_lib.get_point())
Run Code Online (Sandbox Code Playgroud)

如何将返回值设置为POINT带有 value 的结构{1, 2}

jsb*_*eno 5

您所问的并不是您示例中的唯一问题。只是为了回答您首先提出的问题:您必须注释 C 函数返回类型,以便 ctypes 知道它是一个内存地址 - 否则默认情况下它是一个(4 字节)整数(而在任何 64 位操作系统中,指针是8 字节长)。

然后,您可以使用 POINT 类中的(隐藏)“from_address”方法创建 Python 端 POINT 结构:

test_lib.get_point.restype = c_void_p
p = POINT.from_address(test_lib.get_point())

print(p.x, p.y)
Run Code Online (Sandbox Code Playgroud)

然而,在此之前,您在 C 端有一个更基本的问题:您在示例中声明的 POINT 结构仅在get_point运行时存在,并在运行后被释放。上面的代码会导致分段错误。

您的 C 代码必须正确分配内存。而且,您应该采取措施来释放您在 C 中分配的数据结构 - 否则您将出现内存泄漏,因为每次调用 C 中的函数都会分配更多内存,而您不会释放它。(请注意,当 Python POINT 对象超出范围时,该内存不会自行释放)。

你的 C 代码可能是这样的:

#include <stdlib.h>
#include <stdio.h>

typedef struct point {
    int x;
    int y;
} POINT;

POINT *get_point()
{
    POINT *p;
    POINT initial = {1, 2};
    p = malloc(sizeof(POINT));
    *p = initial;
    return p;
}

void free_point(POINT *p)
{
    free(p);
}
Run Code Online (Sandbox Code Playgroud)

对于这个 Python 部分:

from ctypes import *
import os

lib_name = '/testlib.so'
test_lib = CDLL(os.getcwd() + lib_name)

class POINT(Structure):
    _fields_ = [('x', c_int),
                ('y', c_int)]

test_lib.get_point.restype = c_void_p

p1 = POINT.from_address( test_lib.get_point())
print (p1.x, p1.y)

test_lib.free_point(byref(p1))
del p1
Run Code Online (Sandbox Code Playgroud)

一切都应该正常。

(为了让这个答案是一个完整的 ctypes 示例,我将添加 GCC 命令来构建 testlib 文件:

gcc -c -fPIC test.c -o test.o
gcc test.o -shared -o testlib.so
Run Code Online (Sandbox Code Playgroud)

  • 谢谢您的回答!正如@JJHakala 在我原来的帖子中提到的,如果我想按值返回“struct”,执行“test_lib.get_point.restype = POINT”也是有效的。不过,这是返回结构指针的一个很好的参考。 (4认同)
  • 结构可以是 C 中的返回类型,尽管我认为出于风格问题通常会避免这样做。http://stackoverflow.com/questions/9653072/return-a-struct-from-a-function-in-c (2认同)