[Tutor] Passing Data to .DLL
Wilson, Pete
Pete.Wilson at atmel.com
Wed Oct 22 22:50:13 CEST 2014
It's working!
I don't understand the line
rx_buf = (c_uint8 * rx_buf_size).from_buffer_copy(string_buf)
or where .from_buffer_copy() came from but it works...
I promise I will not knowingly pass Python strings to C.
Thanks.
> -----Original Message-----
> From: eryksun [mailto:eryksun at gmail.com]
> Sent: Wednesday, October 22, 2014 4:16 AM
> To: Wilson, Pete
> Cc: tutor at python.org
> Subject: Re: [Tutor] Passing Data to .DLL
>
> On Tue, Oct 21, 2014 at 7:04 PM, Wilson, Pete <Pete.Wilson at atmel.com>
> wrote:
> >
> > ProcessIncomingSerialData_t = CFUNCTYPE(None, POINTER(c_uint8),
> > c_uint16) process_incoming_serial_data =
> > pt_dll.ProcessIncomingSerialData
> process_incoming_serial_data.argtypes
> > = [ProcessIncomingSerialData_t]
>
> ProcessIncomingSerialData takes two parameters: uint8_t *rx_buf and
> uint16_t size.
>
> process_incoming_serial_data.argtypes = [POINTER(c_uint8),
> c_uint16]
> process_incoming_serial_data.restype = None
>
> The buffer parameter isn't const, so pass a copy of string_buf.
>
> size = len(string_buf)
> rx_buf = (c_uint8 * size).from_buffer_copy(string_buf)
> process_incoming_serial_data(rx_buf, size)
>
> I'm going to meander off topic a bit to give you a warning...
>
> Python strings are immutable by contract, so don't pass them directly
> to C functions that might modify them. String immutability makes
> interning possible, sometimes just locally in the code object and
> sometimes globally in the interpreter. Here's an example of both in
> CPython 2.7:
>
> import abc
> from ctypes import *
>
> def test():
> s = 'abc'
> a = cast(s, POINTER(c_char * 3))[0]
> a[:] = 'cba'
> print 'abc'
>
> >>> test.__code__.co_consts
> (None, 'abc', 3, 0, 'cba')
>
> Notice that the 2nd constant in co_consts is 'abc'. This gets stored to
> s and later printed. In between I use ctypes to reverse it. So what
> gets printed? If you guessed "cba", you're right.
>
> >>> test()
> cba
>
> Look at the constants now:
>
> >>> test.__code__.co_consts
> (None, 'cba', 3, 0, 'cba')
>
> So how about referencing the abc module?
>
> >>> abc
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> NameError: name 'abc' is not defined
>
> OK, but do you think we can use cba instead?
>
> >>> cba
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> NameError: name 'cba' is not defined
>
> This is yet another problem with mucking with the internal state of an
> immutable object. Equal objects are supposed to hash the same. 'cba'
> is now equal to the interned 'abc' string that I reversed, but it
> probes to a different slot in the dict's hash table.
>
> >>> test.__code__.co_consts[1] == 'cba'
> True
> >>> hash(test.__code__.co_consts[1]) == hash('cba')
> False
>
> OTOH, a new 'abc' string probes to the same slot in the hash table, but
> it's no longer equal (i.e. it gets handled as a hash collision).
>
> >>> test.__code__.co_consts[1] == 'abc'
> False
> >>> hash(test.__code__.co_consts[1]) == hash('abc')
> True
>
> This breaks dict lookup unless we use the interned string itself:.
>
> >>> globals()[test.__code__.co_consts[1]]
> <module 'abc' from '/usr/lib/python2.7/abc.pyc'>
>
> So the moral is only pass Python strings to C functions that promise
> (scout's honor) to not modify them. If the parameter isn't const, err
> on the side of caution; copy the string to a ctypes buffer.
More information about the Tutor
mailing list