2013-05-22 10 views
8

Sto provando a usare i ctypes per creare un array char * in python da passare a una libreria per il popolamento con stringhe. Mi aspetto 4 stringhe non più lunghe di 7 caratteri ciascuna.Python che usa i ctypes per passare un array char * e popola i risultati

Il mio codice py assomiglia a questo

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

continuo a ricevere errori di segmentazione quando si tenta di eseguire questo codice . Ho creato un test da C che funziona perfettamente ma in Python devo impostare l'array di puntatori in modo errato o qualcosa del genere. Sembra di arrivare al secondo nodo nel ciclo e quindi avere un problema come ho visto sputando i dati nella riga di comando. Qualsiasi intuizione sarebbe molto apprezzata.

risposta

9

Il seguente codice funziona:

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 (compilato per libtest.so con gcc test.c -o libtest.so -shared -fPIC):

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

Come ha detto Aya, è necessario assicurarsi che ci sia spazio per la terminazione zero. Ma penso che il tuo problema principale sia stato il fatto che il buffer delle stringhe è stato garbage collection o qualcosa di simile, poiché non c'era più un riferimento diretto ad esso. Oppure qualcos'altro sta causando problemi nel processo di creazione dei buffer di stringa quando non ci sono riferimenti per loro. Ad esempio ciò comporta quattro volte lo stesso indirizzo invece di diversi indirizzi:

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

È inoltre possibile creare una matrice 2D per il buffer: 'string_buffers = ((ctypes.c_char * 8) * 4)()'. Ripeterà lo stesso quando definirai 'puntatori' nella riga successiva. – eryksun

2

non posso (facilmente) verificare il codice, ma sulla base di quello che hai detto, la mia ipotesi sarebbe il problema sta nella linea ...

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

Secondo la documentazione Python per create_string_buffer() ...

init_or_size deve essere un numero intero che specifica la dimensione della matrice, o una stringa che sarà utilizzato per inizializzare gli elementi di matrice.

Se una stringa viene specificata come primo argomento, il buffer viene reso un elemento più grande della lunghezza della stringa in modo che l'ultimo elemento in l'array sia un carattere di terminazione NUL. Un intero può essere passato come secondo argomento che consente di specificare la dimensione dell'array se non si deve utilizzare la lunghezza della stringa .

... il che implica che è la creazione di un char[7], ma un strcpy() tenterà di copiare il NULL terminatore di una stringa, quindi se il vostro massimo "nome di nodo" lunghezza è di sette caratteri, avrete bisogno di un char[8] a tieni premuto il NULL, anche se potresti scappare usando memcpy(array[i], nodes[i], 7) invece di strcpy().

In entrambi i casi, è probabilmente più sicuro utilizzare create_string_buffer(8).

3

In questa linea:

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

Stai creando un singolo buffer di 7 byte, poi cercando di utilizzare per tenere 4 puntatori di caratteri (che sono probabilmente 4 byte ciascuno), e quindi anche la copia di 4 Stringhe da 8 byte negli indirizzi casuali a cui potrebbe capitare di puntare. È necessario allocare un buffer per ogni stringa e anche allocare l'array di puntatori. Qualcosa di simile a questo:

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