2016-07-01 12 views
5

Sto avendo difficoltà di minzione stringa da Python a C da ctypes:Problema con il passare stringa da Python a C condiviso lib utilizzando ctypes

Il mio codice C (compilato in un hello.so)

... 
typedef struct test{ 
    unsigned int a; 
    unsigned char* b; 
} my_struct; 

int hello(my_struct *in) { 
    FILE *fp; 
    ... 
    fprintf(fp, "%d\t%s\n", in->a, in->b); 
    fclose(fp); 
    return 0; 
} 
codice

mio Python:

... 
from ctypes import * 
... 
class TEST_STRUCT(Structure): 
    _fields_ = [("a", c_int), 
       ("b", c_char_p)] 
... 
    hello_lib = ctypes.cdll.LoadLibrary("hello.so") 
    hello = hello_lib.hello 
    hello.argtypes = [POINTER(TEST_STRUCT)] 
    name = create_string_buffer(b"test") 
    hello_args = TEST_STRUCT(1, name) 
    hello(ctypes.byref(hello_args)) 
... 

ottengo l'errore: hello_args = TEST_STRUCT (1, nome) TypeError: atteso stringa, c_char_Array_5 trovato

Ho provato a cambiare c_char_p in c_wchar_p o c_char * 5 o c_wchar * 5 ecc. A volte può funzionare senza errori, il primo parametro int della struct può essere stampato correttamente, ma non il secondo puntatore di stringa, il migliore I può ottenere è solo il primo carattere 't' al posto dell'intera parola "test".

BTW, la mia versione python3 è 3.3.0

+0

Non so nulla sull'invio di dati tra C e Python, ma cosa succede quando assegni il nome come 'name =" test "'? –

+0

Se faccio Python come questo: hello_lib = ctypes.cdll.LoadLibrary ("hello.so") ciao = hello_lib.hello hello.argtypes = [POINTER (TEST_STRUCT)] #name = create_string_buffer (b "di prova ") name = "test" hello_args = TEST_STRUCT (1, nome) ciao (ctypes.byref (hello_args)) ottengo: TypeError: byte o indirizzo intero attesi anziché esempio str – Alex

+0

Chissà se che si riferisce a un oggetto byte 'nome = byte (" nome "," utf-8 ")' –

risposta

1

La soluzione dipende dal fatto che è necessario il tipo di dati per essere mutabile (dal punto di vista di Python).

Se non è necessario che i dati siano modificabili, non preoccuparsi del costruttore del buffer. Basta passare l'oggetto bytes direttamente al costruttore TEST_STRUCT. per esempio.

from ctypes import * 

class TEST_STRUCT(Structure): 
    _fields_ = [("a", c_int), 
       ("b", c_char_p)] 

hello_args = TEST_STRUCT(1, b"test") 

Se avete bisogno di un buffer variabile, allora è necessario specificare il tipo di char* leggermente diverso nella classe TEST_STRUCT. per esempio.

from ctypes import * 

class TEST_STRUCT(Structure): 
    _fields_ = [("a", c_int), 
       ("b", POINTER(c_char))] # rather than c_char_p 

name = create_string_buffer(b"test") 
hello_args = TEST_STRUCT(1, name) 

c_char_p contro POINTER(c_char)

Apparentemente, mentre questi due appaiono simili sono leggermente differenti. POINTER(c_char) è per qualsiasi buffer di dati char. c_char_p è specifico per stringhe con terminazione NULL. Come effetto collaterale di questa condizione, tutti gli oggetti c_char_p sono immutabili (sul lato python) in modo da rendere più semplice l'applicazione di questa garanzia. per esempio. {65, 66, 67, 0} è una stringa ("ABC"), mentre {1, 2, 3} non lo è.

+0

Puoi spiegare la differenza tra 'c_char_p' e' POINTER (c_char) '? Pensavo fossero la stessa cosa – Snorfalorpagus

+1

Aggiunta una modifica per chiarire. La differenza non è immediatamente evidente e non è ben descritta dalla documentazione. – Dunes

Problemi correlati