Can partial structs figure out the correct integer type?

30 views
Skip to first unread message

Alex Willmer

unread,
Aug 19, 2022, 3:36:23 PM8/19/22
to python-cffi
I'm trying to wrap scandir(), using a partial dirent struct

typedef int... ino_t;
struct dirent {
     ino_t d_ino;
     int d_type; // actually __uint8_t in header, on macOS 12
     char d_name[];
     ...;
};
can cffi & the compiler figure out the correct integer type for d_type (like they do for ino_t)? Or do I need to declare the exact (possibly platform dependant) type?

Experimentation suggests cffi knows the correct type, but it isn't applied

>>> import _scanwalk
>>> namelist = _scanwalk.ffi.new('struct dirent ***namelist')
>>> _scanwalk.lib.scandir(b'demo', namelist, _scanwalk.ffi.NULL, _scanwalk.ffi.NULL)
4
>>> namelist[0][0].d_name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ffi.error: struct dirent: wrong size for field 'd_type' (cdef says 4, but C compiler says 1). fix it or use "...;" as the last field in the cdef for struct dirent to make it flexible

I'm using cffi 1.15.1, CPython 3.10.5, and macOS 12 on arm64. The full code is https://github.com/moreati/scanwalk/blob/cffi-tryout/scanwalk_build.py

With thanks, Alex

Armin Rigo

unread,
Aug 20, 2022, 3:12:30 PM8/20/22
to pytho...@googlegroups.com
Hi Alex,

On Fri, 19 Aug 2022 at 21:36, Alex Willmer <al...@moreati.org.uk> wrote:
> typedef int... ino_t;
> struct dirent {
> ino_t d_ino;
> int d_type; // actually __uint8_t in header, on macOS 12
> char d_name[];
> ...;
> };
> can cffi & the compiler figure out the correct integer type for d_type (like they do for ino_t)? Or do I need to declare the exact (possibly platform dependant) type?
>
> Experimentation suggests cffi knows the correct type, but it isn't applied

Right, that's a use case that is not supported at the moment. CFFI
doesn't know the type; it just checks that the size is correct, which
is not the same thing. For example, it doesn't know if the integer
type is signed or unsigned, which is quite important in this case.

It would be possible to find out the exact type for an integer field
of a named struct. But it would not be possible to do it in general.
For example, it becomes harder and harder if the struct has no name,
if the integer type is that of an array field or an "int **field", and
so on. It has been a long time now but I think I tried to come up
with a way that works all the time and failed. That's why the rules
of using "int..." only work in very specific situations. (Note that
just getting the size of anything is much easier in C, because
sizeof(x) does not evaluate the expression 'x'; it would also not be a
problem if we could rely on a gcc extension like typeof(), but it
wouldn't work everywhere.)


A bientôt,

Armin Rigo

Alex Willmer

unread,
Aug 21, 2022, 6:35:53 PM8/21/22
to python-cffi
On Saturday, 20 August 2022 at 20:12:30 UTC+1 Armin Rigo wrote:
On Fri, 19 Aug 2022 at 21:36, Alex Willmer <al...@moreati.org.uk> wrote:
> Experimentation suggests cffi knows the correct type, but it isn't applied

Right, that's a use case that is not supported at the moment. CFFI
doesn't know the type; it just checks that the size is correct, which
is not the same thing. For example, it doesn't know if the integer
type is signed or unsigned, which is quite important in this case.

Thsnk you, that makes sense. I'll submit a MR to mention it explictly in the docs.
Reply all
Reply to author
Forward
0 new messages