[vlc-devel] RFC: type-punning between (future) vlc_frame_t and vlc_data_t

Thomas Guillem thomas at gllm.fr
Fri Apr 26 09:47:37 CEST 2019


Question following my remark on the "[PATCH 00/17] RFC Split block_t into 2 different data containers" thread:

 "- Code duplication between data.c and frame.c and also between data_helper.h and frame_helper.h: This code is far from trivial and should not be duplicated. We don't want to fix 2 files each time we need to fix a bug. The only way I see to solve this issue is to include vlc_data_t from vlc_frame_t and have generic vlc_data_t functions working with vlc_frame_t."

I wonder if it is possible to include vlc_data_t from vlc_frame_t without renaming all variables (in order to avoid a s/frame->p_buffer/frame->data.p_buffer/ change). Actually, it is possible in C by using anonymous unions and structs but is it allowed ?

cf. https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Type-punning

PS:  ISO C++ prohibits anonymous structs so we will have to rename all C++ code that touch vlc_frame_t

Here is a sample to show what I would to do in VLC:

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
#include <inttypes.h>

#define DATA_MEMBERS \
    uint8_t *buf; \
    size_t size; \
    size_t maxsize; \
    void *start; \

struct data {
    DATA_MEMBERS
    struct data *next;
};

struct frame
{
    union
    {
        struct data d;
#ifndef __cplusplus
        /* ISO C++ prohibits anonymous structs*/
        struct {
            DATA_MEMBERS
            struct frame *next;
        };
#endif
    };

    int64_t pts;
    int64_t dts;
};


static void data_do_something(struct data *data)
{
    data->buf += 10;
    data->size -= 10;
}

static inline void frame_do_something(struct frame *frame)
{
    data_do_something(&frame->d);
}

static void frame_do_specific_thing(struct frame *frame)
{
    frame->buf -= 10;
    frame->size += 10;
}

static void frame_print(struct frame *frame)
{
    fprintf(stderr, "frame: data: %p %zu/%zu vs "
            "%p %zu/%zu, pts: %" PRId64 "\n",
            frame->d.buf, frame->d.size, frame->d.maxsize,
            frame->buf, frame->size, frame->maxsize, frame->pts);
}


int main(void)
{
    struct frame frame;
    frame.d.size = frame.d.maxsize = 42;
    frame.d.start = malloc(frame.d.size);
    frame.d.buf = (uint8_t *) frame.d.start;
    frame.d.next = NULL;
    assert(frame.d.buf);
    frame.pts = frame.dts = 72;

    frame_print(&frame);
    frame_do_something(&frame);
    frame_print(&frame);
    frame_do_specific_thing(&frame);
    frame_print(&frame);

    frame.next = &frame;
    frame.d.next = &frame.d;

    free(frame.d.start);
    return 0;
}


More information about the vlc-devel mailing list