ctypes.c_void_p(-1) might not be C return (void *) -1

Thomas Heller theller at python.net
Fri Sep 29 22:06:57 CEST 2006


p.lavarre at ieee.org schrieb:
>> I've started a wiki page where I already added an entry about the above question.
>> Do you think the entry would have answered your question?
>> http://starship.python.net/crew/theller/moin.cgi/CodeSnippets
> 
> As concise as I now can imagine, yes thank you.
> 
> I see the main point leads: "The truth value of any NULL ctypes pointer
> instance is False."  That angle neatly ducks my ongoing newbie
> confusion over a null constructed in Python via c_void_p(0) being
> different from a null constructed in C via return (void *) 0.
> 
>> ...
>> > And so then the next related Faq is:
>> >
>> > Q: How should I test for ((void *) -1)?
>>
>> For me, on Windows, c_void_p(-1).value is the same
>> as c_void_p(0xFFFFFFFF).value, but it is -1 not 0xFFFFFFFF.
> 
> Different results at my desk.  Specifically, I see:
> 
>>>> from ctypes import * ; c_void_p(-1).value
> 4294967295L
>>>>
> 
> in Mac OS X 10.4.7 Python 2.5 r25:51918 and Win XpSp2 Python 2.5
> r25:51908.

You are right, I was using my own private build of ctypes which behaves
differently.  With Python 2.5 on Windows, I get the same as you.

>> Worse, on 64-bit systems c_void_p(-1).value is 184467440737009661615, which
>> is the same as 0xFFFFFFFFFFFFFFFF.
>> So, to be portable, INVALID_HANDLE_VALUE should be defined like this:
>> INVALID_HANDLE_VALUE = c_void_p(-1).value
> 
> Exactly what I should have written, yes, thank you.
> 
> And somewhat generalisable: c_void_p(0).value is None.
> 
> Maybe this is the thing that's been astonishing me: maybe C often does
> return the .value of the pointer, rather than a new instance of the
> POINTER class?
> 
>> and your test would become
>> (ctypes.cast(pv, ctypes.c_void_p).value == INVALID_HANDLE_VALUE
> 
> Yes.
> 
> Mind you, typing out all that noise inspires me to ask, does (pv ==
> INVALID_HANDLE_VALUE) give the wrong answer for any pv other than
> c_void_p(-1)?  In other words, if by convention I get all my pointers
> from C and never construct a pointer in Python except to take its
> value, then can I safely write the more obvious translation of (pv ==
> INVALID_HANDLE_VALUE)?

Well, c_void_p(-1).value is the same as c_void_p(0xFFFFF...) for a sufficient
number of F's, so to speak.  The integer or long value you pass to c_void_p
is masked with a bitmask haing all bits set to '1' as the platform's (void *)
type has.

>> PS: It is inconsistent that the .value of a c_void_p instance is signed on
>> 32-bit systems, and unsigned on 64-bit systems, but it seems we have to live
>> with that.

Obviously, as you discovered, and I confirmed, this is no longer true.  In the Python2.5
ctypes, the value of c_void_p is always unsigned.  I just meant that we have to live
for quite some time with the behaviour of ctypes as implemented, because only bug
fixes can be made to Python 2.5.

Thomas (I'll probably leave for a few days now)




More information about the Python-list mailing list