2016-07-29 38 views
2

返回给定一个简单的C文件:ctypes的结构从库

#include <stdio.h> 

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

POINT get_point() 
{ 
    POINT p = {1, 2}; 
    return p; 
} 

而且我有一个简单的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()) 

如何将我的返回值设置为结构POINT与价值{1, 2}

+0

您可以用标记为'typedef的任何原因'ed'struct'?很无用。如果你不明白这个评论,你必须在开始之前学习'struct's和'typedef'。 – Olaf

+0

@Olaf我一直使用'typedef'作为C中'struct'的别名。那有什么内在的错误吗? –

+0

我没有评论使用'typedef'。但是你的评论证明我的假设是正确的。不要只遵循一种模式,但要学习**为什么**你必须/应该写一些特定的方式! – Olaf

回答

1

你问的是你的例子中唯一的问题。 只是为了回答刚才您的问题:您必须注释C函数返回类型,以便ctypes知道它是一个内存地址 - 否则它默认为(4字节)整数(而在任何64字节操作系统中,指针长8个字节)。

然后你就可以在你点类使用(隐藏) “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) 

之前的作品,但是,你有一个更根本的问题在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); 
} 

而与此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 

一切都应该只是工作。

(只是让这个答案是一个完整的ctypes的例子,我将添加 GCC命令编译TESTLIB文件:

gcc -c -fPIC test.c -o test.o 
gcc test.o -shared -o testlib.so 

+0

谢谢你的回答!正如@ J.J.Hakala在我原来的文章中提到的,如果我想通过值返回'struct',那么执行'test_lib.get_point.restype = POINT'也是有效的。不过,这是返回结构指针的很好的参考。 –

+0

我不确定返回结构“by_value”是否可以工作 - 当然,除了语法之外。它必须存在于记忆中的某个地方。 – jsbueno

+0

结构可以是C语言中的返回类型,但我认为它通常是作为样式避免的。 http://stackoverflow.com/questions/9653072/return-a-struct-from-a-function-in-c –