Alloca вместо локальной переменной в Alsa
Я использовал пример программы C ALSA в качестве справочной и пробежал по следующему коду:
...
snd_ctl_event_t *event;
snd_ctl_event_alloca(&event);
...
Основываясь на исходном коде ALSA, snd_ctl_event_alloca
это макрос, который вызывает __snd_alloca
который является макросом, который, наконец, расширяется до следующей эквивалентной строки для snd_ctl_event_alloca(&event);
(с некоторым простым упрощением):
event = (snd_ctl_event_t *) alloca(snd_ctl_event_sizeof());
memset(event, 0, snd_ctl_event_sizeof());
где snd_ctl_event_sizeof()
реализуется только один раз во всей библиотеке как:
size_t snd_ctl_event_sizeof()
{
return sizeof(snd_ctl_event_t);
}
Итак, мой вопрос, не является ли весь этот процесс эквивалентным простому выполнению:
snd_ctl_event_t event = {0};
Для справки, это макросы:
#define snd_ctl_event_alloca(ptr) __snd_alloca(ptr, snd_ctl_event)
#define __snd_alloca(ptr,type) do { *ptr = (type##_t *) alloca(type##_sizeof()); memset(*ptr, 0, type##_sizeof()); } while (0)
Разъяснения:
- Первый блок кода выше находится в начале тела функции, а не во вложенном блоке.
РЕДАКТИРОВАТЬ
Как выясняется (из того, что я понимаю), занимаюсь:
snd_ctl_event_t event;
дает storage size of 'event' isn't known
ошибка, потому что snd_ctl_event_t
по-видимому, непрозрачная структура, которая определяется в частном порядке. Поэтому единственным вариантом является динамическое распределение.
1 ответ
Поскольку это непрозрачная структура, цель всех этих действий, очевидно, состоит в том, чтобы реализовать непрозрачный тип данных, сохраняя при этом все "за" и преодолевая по крайней мере некоторые из их "минусов".
Одна существенная проблема с непрозрачными типами данных заключается в том, что в стандартном C вы по существу вынуждены динамически размещать их в непрозрачной функции библиотеки. Невозможно неявно объявить непрозрачный объект локально. Это отрицательно влияет на эффективность и часто вынуждает клиента осуществлять дополнительное управление ресурсами (т. Е. Не забывать освобождать объект, когда он больше не нужен). Выставление точного размера непрозрачного объекта (через функцию в данном случае) и опора на alloca
Выделить хранилище как можно ближе к более эффективному и довольно беззаботному локальному объявлению.
Если срок службы всей функции не требуется, alloca
можно заменить на VLA, но авторы, вероятно, не хотели / не могли использовать VLA. (Я бы сказал, что использование VLA еще больше приблизит эмуляцию к истинному локальному объявлению.)
Часто для реализации той же технологии непрозрачный размер объекта может быть представлен как константа времени компиляции в заголовочном файле. Однако использование функции имеет дополнительное преимущество, заключающееся в том, что нет необходимости перекомпилировать весь проект, если размер объекта в этой изолированной библиотеке изменяется (как @R. Отмечено в комментариях).
Предыдущая версия ответа (пункты ниже все еще применимы, но, видимо, вторичны):
Это не совсем эквивалентно, так как alloca
игнорирует основанные на сфере действия правила жизни. Время жизни alloca
Е-память распространяется до конца функции, в то время как время жизни локального объекта распространяется только до конца блока. Это может быть плохо, это может быть хорошо, в зависимости от того, как вы его используете.
В таких ситуациях, как
some_type *ptr;
if (some condition)
{
...
ptr = /* alloca one object */;
...
}
else
{
...
ptr = /* alloca another object */;
...
}
разница в семантике может быть решающей. Будь то ваш случай или нет - я не могу сказать из того, что вы опубликовали до сих пор.
Другое несвязанное различие в семантике заключается в том, что memset
обнулит все байты объекта, в то время как = { 0 }
не гарантируется обнуление байтов заполнения (если есть). Это может быть важно, если объект затем используется с некоторыми двоичными API (например, отправляется в сжатый поток ввода-вывода).