2016-07-29 28 views
2

eine einfache C-Datei Gegeben:ctypes struct aus der Bibliothek zurück

#include <stdio.h> 

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

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

Und ich habe eine einfache Python-Datei:

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()) 

Wie kann ich meinen zurückgegebene Wert auf die Struktur POINT mit Werten gesetzt {1, 2} ?

+0

Gibt es Gründe, Sie einen Tag für eine 'typedef verwenden 'ed' struct'? Ziemlich nutzlos. Wenn Sie diesen Kommentar nicht verstehen, müssen Sie sich vor dem Start über 'struct's und' typedef' informieren. – Olaf

+0

@Olaf Ich habe immer 'typedef' für' struct's in C für Aliase verwendet. Liegt da etwas falsch daran? –

+0

Ich habe nicht kommentiert mit 'typedef'. Aber dein Kommentar beweist, dass meine Annahme richtig ist. Folgen Sie nicht nur einem Muster, sondern lernen Sie, warum Sie etwas auf eine bestimmte Weise schreiben müssen/sollten! – Olaf

Antwort

1

Was Sie fragen, ist das einzige Problem in Ihrem Beispiel. Nur um zu antworten, was Sie zuerst gefragt haben: Sie müssen den Rückgabetyp der C-Funktion annotieren, so dass Ctypes wissen, dass es eine Speicheradresse ist - ansonsten ist es standardmäßig eine (4 Byte) Ganzzahl (während in jedem 64-Byte-Betriebssystem Zeiger sind) sind 8 Bytes lang).

Dann können Sie Python Seite POINT Strukturen schaffen, indem die (versteckte) „from_address“ Methode in der POINT-Klasse:

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

print(p.x, p.y) 

Bevor das funktioniert, aber Sie haben eine grundlegende Frage auf der C Seite: Die POINT-Struktur, die Sie in Ihrem Beispiel deklarieren, existiert nur, während get_point ausgeführt wird, und wird anschließend freigegeben. Der obige Code würde zu einem Segmentierungsfehler führen.

Ihr C-Code muss Speicher richtig zuordnen. Außerdem sollten Sie Vorkehrungen treffen, um die Zuordnung von Datenstrukturen, die Sie in C zugeordnet haben, zu verhindern. Andernfalls entstehen Speicherlecks, da jeder Aufruf der Funktion in C mehr Speicher zuweist und Sie diesen nicht freigeben. (Beachten Sie, dass dieser Speicher nicht von selbst freigegeben wird, wenn das Python POINT-Objekt den Gültigkeitsbereich verlässt).

Ihr C-Code könnte so aussehen:

#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); 
} 

Und mit diesem Python Teil:

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 

alles sollte einfach funktionieren.

(nur so, dass diese Antwort ein komplettes ctypes Beispiel ist, füge ich die GCC die testlib-Datei erstellen Befehle:

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

)

+0

Vielen Dank für die Antwort! Wie von @ J.J.Hakala in meinem ursprünglichen Beitrag erwähnt, ist das Ausführen von 'test_lib.get_point.restype = POINT' auch dann gültig, wenn ich die' struct' nach Wert zurückgeben möchte. Dies ist eine großartige Referenz für das Zurückgeben von Strukturzeigern. –

+0

Ich bin nicht sicher, ob die Rückgabe einer Struktur "by_value" überhaupt funktioniert - neben der Syntax natürlich. Es muss irgendwo in der Erinnerung existieren. – jsbueno

+0

Eine Struktur kann ein Rückgabetyp in C sein, obwohl ich denke, dass es in der Regel als eine Frage des Stils vermieden wird. http://stackoverflow.com/questions/9653072/return-a-struct-from-a-function-in-c –