Search code examples
arrayscffmpegcastingmacros

Typecasting an array in C


I was reading FFMPEG source code on extracting audio and I found these macros. What do these macros do?

#define REINTERPRET_CAST(type, variable) C_CAST(type, variable)
#define STATIC_CAST(type, variable) C_CAST(type, variable)
#define C_CAST(type, variable) ((type)variable)

//used like this
int value = 0;
int sampleIndex = 0;
uint8_t* buffer = calloc(50, sizeof(uint8_t));

value = REINTERPRET_CAST(uint8_t*, buffer)[sampleIndex];
value = REINTERPRET_CAST(int16_t*, buffer)[sampleIndex];
value = REINTERPRET_CAST(int32_t*, buffer)[sampleIndex];
value = REINTERPRET_CAST(int64_t*, buffer)[sampleIndex];
int ret = STATIC_CAST(float, *REINTERPRET_CAST(double*, &value));

Solution

  • //used like this

    Used like in this code they do nothing meaningful - convert pointer to int and assign to int vartable (abstracting from the wrong syntax)

    If they are used like this:

    uint64_t value = *REINTERPRET_CAST(int64_t*, buffer + sampleIndex);
    

    BTW the macro is wrong as well

    #define C_CAST(type, variable) ((type)(variable))
    

    Then it is called pointer punning and it invokes Undefined Behaviour violating strict aliasing rules.

    It should be done this way:

    #define pune(var, X) _Generic((var), \
                  uint16_t *: pune16, \
                  uint32_t *: pune32,  \
                  uint64_t*: pune64  \
                  )(var, X)
    
    
    uint16_t pune16(uint16_t *val, const void *ptr)
    {
        memcpy(val, ptr, sizeof(*val));
        return *val;
    }
    
    uint32_t pune32(uint32_t *val, const void *ptr)
    {
        memcpy(val, ptr, sizeof(*val));
        return *val;
    }
    
    uint64_t pune64(uint64_t *val, const void *ptr)
    {
        memcpy(val, ptr, sizeof(*val));
        return *val;
    }
    

    example usage:

    void foo(void *v)
    {
        uint32_t x;
        x = pune(&x, v);
        printf("%"PRIu32"\n,",  x);
    }