2013-05-22 9 views
8

Ich versuche Ctypes zu verwenden, um ein char * -Array in Python an eine Bibliothek zum Auffüllen mit Strings übergeben zu übergeben. Ich erwarte 4 Strings zurück mit nicht mehr als jeweils 7 Zeichen Länge.Python mit ctypes übergeben ein Char * -Array und füllen Ergebnisse

Mein py Code sieht wie folgt aus

testlib.py

from ctypes import * 
primesmile = CDLL("/primesmile/lib.so") 

getAllNodeNames = primesmile.getAllNodeNames 
getAllNodeNames.argtypes = [POINTER(c_char_p)] 
results = (c_char_p * 4)(addressof(create_string_buffer(7))) 
err = getAllNodeNames(results) 

lib.cpp

void getAllNodeNames(char **array){ 
    DSL_idArray nodes; //this object returns const char * when iterated over 
    network.GetAllNodeIds(nodes); 
    for(int i = 0; i < (nodes.NumItems()); i++){ 
    strcpy(array[i],nodes[i]); 
    } 
} 

Ich halte Segmentierung Fehler bekommen, wenn ich versuche, diesen Code auszuführen . Ich habe einen Test von C erstellt, der perfekt funktioniert, aber in Python muss ich das Zeiger-Array falsch oder etwas einrichten. Es scheint, zum zweiten Knoten in der Schleife zu kommen und dann ein Problem zu haben, wie ich vom Ausspucken von Daten in die Befehlszeile gesehen habe. Jede Einsicht würde sehr geschätzt werden.

Antwort

9

Der folgende Code funktioniert:

Test.py:

import ctypes 
lib = ctypes.CDLL("./libtest.so") 
string_buffers = [ctypes.create_string_buffer(8) for i in range(4)] 
pointers = (ctypes.c_char_p*4)(*map(ctypes.addressof, string_buffers)) 
lib.test(pointers) 
results = [s.value for s in string_buffers] 
print results 

test.c (kompiliert mit gcc test.c -o libtest.so -shared -fPIC libtest.so):

#include <string.h> 
void test(char **strings) { 
    strcpy(strings[0],"this"); 
    strcpy(strings[1],"is"); 
    strcpy(strings[2],"a"); 
    strcpy(strings[3],"test!"); 
} 

Wie Aya sagte, sollten Sie sicherstellen, dass es Raum für die abschließende Null. Aber ich denke, Ihr Hauptproblem war, dass der String-Puffer Müll gesammelt wurde oder etwas Ähnliches, da es keinen direkten Bezug mehr gab. Oder etwas anderes verursacht beim Erstellen der Zeichenfolgenpuffer Probleme, wenn für sie keine Referenzen gespeichert werden. Zum Beispiel ergibt dies viermal die gleiche Adresse anstelle verschiedener Adressen:

import ctypes 
pointers = [ctypes.addressof(ctypes.create_string_buffer(8)) for i in range(4)] 
print pointers 
+3

Sie können auch einen 2D-Array für den Puffer erstellen: 'string_buffers = ((ctypes.c_char * 8) * 4)()'. Es wird dasselbe durchlaufen, wenn Sie in der nächsten Zeile "Zeiger" definieren. – eryksun

2

kann ich nicht (leicht), um den Code testen, sondern auf dem, was Sie gesagt haben, wäre meine Vermutung das Problem in der Linie liegt ...

results = (c_char_p * 4)(addressof(create_string_buffer(7))) 

Nach der Python-Dokumentation für create_string_buffer() ...

init_or_size muss eine ganze Zahl sein, die die Größe des Feldes angibt, oder eine Zeichenfolge, die verwendet werden, um die Array-Elemente zu initialisieren.

Wenn ein String, der als erstes Argument angegeben wird, wird der Puffer ein Element größer ist als die Länge der Zeichenfolge, so daß das letzte Element in das Array ein NUL Abschlusszeichen. Eine Ganzzahl kann als zweites Argument übergeben werden, mit dem die Größe des Arrays angegeben werden kann, wenn die Länge des Strings nicht verwendet werden soll.

... die es die Schaffung eines char[7] impliziert, sondern ein strcpy() wird versuchen, den NULL Terminator für eine Zeichenfolge zu kopieren, so dass, wenn Ihr Maximum „Knotenname“ Länge sieben Zeichen ist, werden Sie eine char[8] müssen Halten Sie die NULL, obwohl Sie mit der Verwendung memcpy(array[i], nodes[i], 7) statt strcpy() durchkommen können.

Wie auch immer, es ist wahrscheinlich am sichersten, stattdessen create_string_buffer(8) zu verwenden.

3

In dieser Zeile:

results = (c_char_p * 4)(addressof(create_string_buffer(7))) 

Sie einen einzigen Puffer von 7 Bytes zu schaffen, dann 4 Zeichenzeiger versuchen, es zu verwenden, halten (die jeweils 4 Bytes wahrscheinlich sind), und kopieren Sie dann auch 4 8-Byte-Strings in die zufälligen Adressen, auf die es möglicherweise zeigt. Sie müssen für jede Zeichenfolge einen Puffer reservieren und auch das Array von Zeigern zuweisen. Etwas wie folgt aus:

s = [] 
for i in range(4): 
    s[i] = create_string_buffer(8) 
results = (c_char_p * 4)(s); 
Verwandte Themen