Snaipe / libcsptr

Smart pointers for the (GNU) C programming language
https://snai.pe/c/c-smart-pointers/
MIT License
1.57k stars 143 forks source link

Support structs with flexible array members? #29

Open intelfx opened 8 months ago

intelfx commented 8 months ago

I'd like to extend libcsptr (specifically, the shared_ptr/unique_ptr macros) to handle C99 structs with flexible array members.

I. e.

struct Foo
{
    size_t size;
    char data[];
}

struct Foo *foop = shared_flex(struct Foo, ...);

Easy enough on the surface (add a member + length parameters and calculate the allocation size with a few offsetof and sizeof calls) and so far I came up with this implementation:

#define smart_flex(Kind, Type, Member, Length, ...)                         \
    ({                                                                      \
        struct s_tmp {                                                      \
            CSPTR_SENTINEL_DEC                                              \
            __typeof__(Type) value;                                         \
            f_destructor dtor;                                              \
            struct {                                                        \
                const void *ptr;                                            \
                size_t size;                                                \
            } meta;                                                         \
        } args = {                                                          \
            CSPTR_SENTINEL                                                  \
            __VA_ARGS__                                                     \
        };                                                                  \
        const size_t alloc_size =                                           \
            offsetof (Type, Member)                                         \
            + sizeof (((Type *)0)->Member[0]) * (Length);                   \
        void *var = smalloc(alloc_size, 0, Kind, ARGS_);                    \
        if (var != NULL)                                                    \
            memcpy(var, &args.value, sizeof (Type));                        \
        var;                                                                \
    })

However, including a struct with a flexible array member as a non-last member of another struct is a (now-deprecated) gcc extension.

Any ideas on how to do this properly and preserve the ergonomics of accepting an optional destructor + metadata at the end of the smart_flex() call?