Я читал исходный код FFMPEG по извлечению аудио и нашел эти макросы. Что делают эти макросы?
#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));
Они просто расширяются до тех же обычных явных приведений. Их авторы, вероятно, определили их, чтобы отразить семантику приведения C++ и/или задокументировать причину, по которой приведения хорошо определены.
Предполагая, что я ничего не упускаю, эти макросы просто бесполезны, и просто писать приведения вручную, вероятно, будет проще для всех.
Я нуб. Простите меня за вопрос. Как бы я написал эти макросы вручную?
//используется вот так
Используемые, как в этом коде, они не делают ничего значимого - преобразуют указатель в int и присваивают int vartable (абстрагируясь от неправильного синтаксиса)
Если они используются так:
uint64_t value = *REINTERPRET_CAST(int64_t*, buffer + sampleIndex);
Кстати, макрос тоже неправильный
#define C_CAST(type, variable) ((type)(variable))
Затем это называется каламбуром указателя и вызывает Undefined Behavior, нарушая строгие правила псевдонимов.
Это должно быть сделано следующим образом:
#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;
}
Пример использования:
void foo(void *v)
{
uint32_t x;
x = pune(&x, v);
printf("%"PRIu32"\n,", x);
}
«Это должно быть сделано так» не принимает во внимание [sampleIndex].
@chux-ReinstateMonica buffer + sampleIndex не так ли?
Хм, OP [sampleIndex] включает добавление указателя целевого типа. buffer + sampleIndex — добавление указателя на исходный тип.
@chux-ReinstateMonica Я не знаю, о чем ты говоришь buffer это определенно источник
@chux-ReinstateMonica, вы могли бы просто сказать, что исходный макрос плохой, а не эти комментарии
REINTERPRET_CAST(uint64_t*, buffer)[sampleIndex]
похож на ((uint64_t*) buffer)[sampleIndex]
и имеет доступ к другой части buffer[]
, чем pune64(buffer + sampleIndex);
.
@chux-ReinstateMonica, вы комментируете несуществующий код - ваш комментарий появился через много минут после моего редактирования.
Давайте продолжим обсуждение в чате.
@tstanisl ты не видел memcpy?
Я имею в виду, что нет необходимости играть в функции _Generic и puneN. Только memcpy будет достаточно.
@tstanisl нет, потому что он также должен работать с указателями. Слишком много писать. Компилятор все равно удалит лишние назначения
Пропустите код через препроцессор и посмотрите, во что расширяются макросы.