2014-05-25 14 views
9

Jestem zdezorientowany z tego zachowania różnych wersji Pythona i nie rozumiem, dlaczego?Różne zachowanie ctypów 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 

Jeden działa, podczas gdy drugi daje mi błąd. Który jest prawidłowy ?

Jeśli oba są poprawne, w jaki sposób mogę osiągnąć to samo zachowanie, co 2.7 w 3.3.5? Chcę przekazać wskaźnik znaku do C z Pythona.

+2

W Pythonie 3 użyj 'bytes', tj.' C = b "witaj" '. Instancja 'c_char_p' wskazuje na prywatny bufor obiektu' bytes', więc używaj tego tylko dla parametrów 'const', które nie modyfikują łańcucha. – eryksun

+0

@eryksun Jeśli mógłbyś to dodać jako przyczynę zmiany w python3, byłbym szczęśliwy, gdyby mógł to zaakceptować. –

Odpowiedz

13

c_char_p jest podklasą _SimpleCData, z _type_ == 'z'. Metoda __init__ wywołuje typ setfunc, który dla prostego typu 'z' to z_set.

W języku Python 2, z_set function (2.7.7) jest napisane, aby obsługiwać zarówno ciągi znaków str i unicode. Przed wersją Python 3, str jest łańcuchem 8-bitowym. CPython 2.x str wewnętrznie stosuje łańcuch zakończony znakiem C (tj. Tablicę bajtów zakończoną przez \0), dla której z_set może wywoływać PyString_AS_STRING (tj. Uzyskać wskaźnik do wewnętrznego bufora obiektu str). Ciąg znaków unicode musi najpierw zostać zakodowany dla ciągu bajtów. z_set obsługuje to kodowanie automatycznie i zachowuje odwołanie do zakodowanego ciągu w atrybucie _objects.

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

W Windows kodowanie ciąg domyślne ctypes jest 'mbcs' z obsługi błędów zestaw do 'ignore'. Na wszystkich innych platformach kodowanie domyślne to 'ascii', z obsługą błędów . Aby zmienić ustawienie domyślne, zadzwoń pod numer ctypes.set_conversion_mode. Na przykład: set_conversion_mode('utf-8', 'strict').

W języku Python 3,(3.4.1) nie dokonuje automatycznej konwersji str (obecnie Unicode) na bytes. Paradygmat został zmieniony w Pythonie 3, aby ściśle dzielić ciągi znaków z danych binarnych. Domyślne konwersje zostały usunięte, podobnie jak funkcja set_conversion_mode. Musisz minąć obiekt c_char_p o numerze bytes (np. b'spam' lub 'spam'.encode('utf-8')). W CPython 3.x, z_set wywołuje funkcję C-API PyBytes_AsString, aby uzyskać wskaźnik do wewnętrznego bufora obiektu bytes.

Należy zauważyć, że jeśli funkcja C modyfikuje ciąg znaków, należy zamiast tego użyć create_string_buffer do utworzenia tablicy c_char. Poszukaj parametru, który zostanie wpisany jako const, aby wiedzieć, że jest bezpieczny w użyciu c_char_p.

+0

Dziękujemy za szczegółową odpowiedź. –

Powiązane problemy