Accessing struct field metadata from python

13 views
Skip to first unread message

russm

unread,
Mar 28, 2025, 4:26:20 AMMar 28
to python-cffi
Is there any way from python to know the size and type of fields in a struct cdata or given the ctype?

I'm using cffi to deal with some old binary files whose structure is defined in C headers with various structs, so I'm not calling to/from any C code, just a lot of ffi.from_buffer() with a thin python wrapper on top of the returned cdata. The main thing the wrapper does is deal with endianness. The file format is big-endian and my code needs to work on both big and little-endian, so member access lives behind something like

    @property
    def f_nsyms(self):
        return socket.ntohl(self._cdata.f_nsyms)


or perhaps socket.ntohs, or ffi.string, or no transform at all, depending on the field.

I'd rather autogenerate all these accessors instead of having to manually translate it all as boilerplate from C to python. I can get the list of fields from the cdata, but I don't see any way to know "this field is 4 bytes long and will be a python int" or whatever so I can decide what transform is appropriate. Is this possible?

thanks

R.

Armin Rigo

unread,
Mar 28, 2025, 4:44:18 AMMar 28
to pytho...@googlegroups.com
Hi Russm,

On Fri, 28 Mar 2025 at 09:26, russm <russ...@gmail.com> wrote:
> I'd rather autogenerate all these accessors instead of having to manually translate it all as boilerplate from C to python. I can get the list of fields from the cdata, but I don't see any way to know "this field is 4 bytes long and will be a python int" or whatever so I can decide what transform is appropriate. Is this possible?

From the ctype object that describes the struct type, the info is
found in the "fields" attribute. Example:

>>> ffi.cdef("struct s { int a; short b; };")
>>> ffi.typeof("struct s")
<ctype 'struct s'>
>>> ffi.typeof("struct s").fields
[('a', <_cffi_backend.CField object at 0x000001A1F01D38A0>), ('b',
<_cffi_backend.CField object at 0x000001A1F01D3720>)]
>>> ct = ffi.typeof("struct s").fields[1][1].type
>>> ct
<ctype 'short'>
>>> ct.kind
'primitive'
>>> ct.cname
'short'

At this point, you probably need to compare ct.cname to known strings
and check ffi.sizeof(ct). The exact kind of primitive type is not
directly exposed, so it could be integer, bool_t, floating-point,
complex number, or char/wchar_t.


Armin Rigo

russm

unread,
Mar 28, 2025, 9:52:52 AMMar 28
to python-cffi
Oh, that's perfect, thanks! (Bonus for the fields in definition order rather than alphabetical so my repr now matches the struct layout)

At this point, you probably need to compare ct.cname to known strings
and check ffi.sizeof(ct). The exact kind of primitive type is not
directly exposed, so it could be integer, bool_t, floating-point,
complex number, or char/wchar_t.

Yeah I already need to special-case some (epoch second timestamps and some offsets that need to be rebased mainly) but I can get the right default case almost all the time from this so it's a nice win.

thanks

R.
Reply all
Reply to author
Forward
0 new messages