Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does ctypes.c_int completely change its behaviour when put into ctypes Structure?

Tags:

python

ctypes

When I create a variable of type ctype.c_int it reports that type and does not allow any math operations:

In [107]: x = c_int(1)
In [108]: x
Out[108]: c_int(1)
In [109]: x+=1
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
----> 1 x+=1
TypeError: unsupported operand type(s) for +=: 'c_int' and 'int'

In [110]: x+=x
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
----> 1 x+=x
TypeError: unsupported operand type(s) for +=: 'c_int' and 'c_int'

In [111]: type(x)
Out[111]: ctypes.c_int

On the other hand: when I make a structure with c_int inside it is reported as int, allows math operations but still seems to be stored as 32-bit c-integer because it wraps correctly on 32 bit, and honors sign bit at position 31.

In [112]: class REC(ctypes.Structure): _fields_=[('x',ctypes.c_int),('y',ctypes.c_int)]
In [113]: rec = REC()

In [114]: rec.x
Out[114]: 0

In [114]: type(rec.x)
Out[114]: int                       # why not ctypes.c_int ???

In [116]: rec.x+=0x7FFFFFFF         # += works, so it is regular python int ?

In [117]: rec.x
Out[117]: 2147483647

In [118]: rec.x+=1

In [119]: rec.x
Out[119]: -2147483648               # but it honors sign bit at position 31...

In [122]: rec.x=0xFFFFFFFF

In [123]: rec.x
Out[123]: -1

In [124]: rec.x+=1

In [125]: rec.x
Out[125]: 0                         # ...and it wraps on 32 bits, so it is NOT python int!

Can someone explain this behavior? Is there any logic behind this?

like image 762
ardabro Avatar asked Dec 13 '25 19:12

ardabro


1 Answers

The bare c_int has to have two identities: the C object whose addressof may be taken, and the Python object x. The former is an integer, but the latter is not. (Recall that x=2 would just rebind x and would not update the C integer.)

When you put the variable in a structure, ctypes can provide, as a convenience, an attribute-based interface that converts between the C and Python representations. This has its own surprises: store a suitably large value and you’ll see that then rec.x is not rec.x. The manufactured objects are real Python objects, but of course they don’t follow Python rules since they don’t own any data.

The same applies to the bare integer’s value attribute.

Oddly enough, it’s hard to get the equivalent of a bare integer from a structure, so you can’t easily pass a structure member to a function to fill it in.

like image 190
Davis Herring Avatar answered Dec 16 '25 11:12

Davis Herring