2014-05-25 15 views
9

Sono confuso con questo comportamento di diverse versioni di Python e non capisco perché?Comportamento diverso dei ctyp c_char_p?

Python 2.7.5 (default, Aug 25 2013, 00:04:04) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> c="hello" 
>>> a=ctypes.c_char_p(c) 
>>> print(a.value) 
hello 

Python 3.3.5 (default, Mar 11 2014, 15:08:59) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> c="hello" 
>>> a=ctypes.c_char_p(c) 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: bytes or integer address expected instead of str instance 

Uno funziona mentre l'altro mi dà un errore. Quale è corretto ?

Se entrambi sono corretti, come posso ottenere lo stesso comportamento di 2.7 in 3.3.5? Voglio passare il puntatore char a C da python.

+2

In Python 3 si usano 'byte', cioè' c = b "ciao" '. L'istanza di 'c_char_p' punta al buffer privato dell'oggetto' bytes', quindi usalo solo per i parametri 'const' che non modificheranno la stringa. – eryksun

+0

@eryksun Se potessi aggiungere che come risposta per il motivo per cui è cambiato in python3, sarei felice di accettarlo. –

risposta

13

c_char_p è una sottoclasse di _SimpleCData, con _type_ == 'z'. Il metodo __init__ chiama il tipo setfunc, che per il tipo semplice 'z' è z_set.

In Python 2, lo z_set function (2.7.7) viene scritto per gestire entrambe le stringhe str e unicode. Prima di Python 3, str è una stringa a 8 bit. CPython 2.x str utilizza internamente una stringa C terminata da null (vale a dire una matrice di byte terminata da \0), per cui z_set può chiamare PyString_AS_STRING (ad esempio ottenere un puntatore al buffer interno dell'oggetto str). Una stringa unicode deve prima essere codificata in una stringa di byte. z_set gestisce questa codifica automaticamente e mantiene un riferimento alla stringa codificata nell'attributo _objects.

>>> c = u'spam' 
>>> a = c_char_p(c) 
>>> a._objects 
'spam' 
>>> type(a._objects) 
<type 'str'> 

Su Windows, la stringa di codifica ctypes default è 'mbcs', con gestione degli errori impostato su 'ignore'. Su tutte le altre piattaforme la codifica predefinita è 'ascii', con la gestione degli errori 'strict'. Per modificare l'impostazione predefinita, chiamare ctypes.set_conversion_mode. Ad esempio, set_conversion_mode('utf-8', 'strict').

In Python 3, z_set function (3.4.1) non converte automaticamente str (ora Unicode) in bytes. Il paradigma si è spostato in Python 3 per dividere strettamente le stringhe di caratteri dai dati binari. Le conversioni predefinite di tipo ctype sono state rimosse, così come la funzione set_conversion_mode. Devi passare c_char_p un oggetto bytes (ad esempio b'spam' o 'spam'.encode('utf-8')). In CPython 3.x, z_set chiama la funzione C-API PyBytes_AsString per ottenere un puntatore al buffer interno dell'oggetto bytes.

Si noti che se la funzione C modifica la stringa, è necessario invece utilizzare create_string_buffer per creare un array c_char. Cerca un parametro da digitare come const per sapere che è sicuro usare c_char_p.

+0

Grazie per la tua risposta dettagliata. –

Problemi correlati