2016-07-29 36 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 –