tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: proposal: some pointer and arithmetic utilities



   Date: Fri, 22 Mar 2013 09:08:55 +0200
   From: Alan Barrett <apb%cequrux.com@localhost>

   I don't really see the point of offsetin -- if you have a struct 
   that ends with an array of 1 element, but you want to allocate 
   enough space for the struct plus an array of >1 elements, then why 
   not just do the arithmetic without a macro, and if you do need a 
   macro, then why not give it a name that sounds more like "sizeof"?

We could do the arithmetic without a macro, but it's more complicated
to get that correct.  Compare

        struct foo *f = alloc(offsetin(*f, f_data[n]));

with

        struct foo *f = alloc(sizeof(*f) + sizeof(typeof(f->f_data[0])[n]));

Of course, if I want to avoid typeof (as we seem to do throughout our
tree), I have to know the type of the flexible array member's elements
a priori, and the compiler won't check that for me:

        struct foo *f = alloc(sizeof(*f) + sizeof(double[n]));

This assumes that f_data is a C99 flexible array member, too, not a
one-element array kludged pre-C99 into the same concept.  If you use
one-element arrays like that and assume they work (which we do), the
sizing becomes more complicated -- but offsetin remains the same:

        struct foo *f = alloc(offsetof(struct foo, f_data[0]) +
            sizeof(typeof(f->f_data[0])[n]));

or

        struct foo *f = alloc(sizeof(struct foo) + (n - 1)*sizeof(double));

versus

        struct foo *f = alloc(offsetin(*f, f_data[n]));

Why not a name that sounds more like sizeof?  I just took the name
offsetof and tweaked it, because we're passing an object rather than a
type.  If this were a language extension I'd suggest just using the
name offsetof like we use sizeof for objects and types alike, but this
is just a macro where we can't do that.  I'm open to suggestions for
other names; I'm not wedded to offsetin.

There is one niggly bit: the user of offsetin like this must guarantee
that the arithmetic won't overflow.  This is no worse than the idioms
we currently use, but it would be nice if we had a convenient way to
check for overflow like we do for normal arrays -- calloc(n,
sizeof(x[0])) can check for us that n * sizeof(x[0]) doesn't overflow.

I guess we could have fma_alloc(sizeof(*f), sizeof(f->f_data[0]), n),
where `fma' stands for `fused multiply add' (silly names, I know), but
we'd have to multiply that by all the different allocators we have.

   I also don't see the point of container_of -- why not redesign 
   the code so that the the inner struct has a pointer to the outer 
   struct?

Well, because that requires redesigning the code.  We have various
existing uses of the idiom, and external code -- Linux especially, in
drm -- has many more.  Even if we decide we don't like the idiom, I
think the cost of redesigning code using it is substantially greater
than the cost of encouraging it by adding a safer way to do it.

   Please don't evaluate macro arguments more than once, except in 
   macros whose names are ALL_CAPS.

We already do in roundup, rounddown, roundup2, and powerof2.  This is
wrong, obviously, but at the moment I'm not keen on upcasing lots of
code to fix it, or analyzing the consequences of replacing them all by
static inlines that take uintmax_t, so I figured adding a rounddown2
that also multiply evaluates arguments wouldn't make the situation
substantially worse.

   Since it's not standard C, I think __typeof__ would be preferable 
   to typeof.  My tests show that it's available in gcc, clang, and 
   pcc.

Right -- in the header file I'd use __typeof__.  I meant to ask more
generally about whether this is an appropriate feature to use in our
header files.


Home | Main Index | Thread Index | Old Index