alloca代替alsa中的局部变量

时间:2018-10-15 23:54:06

标签: c alsa alloca libalsa

我使用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 个答案:

答案 0 :(得分:3)

由于它是一个不透明的结构,因此所有这些操作的目的显然是实现一个不透明的数据类型,同时保存所有“优点”并击败至少一些“缺点”。

不透明数据类型的一个突出问题是,在标准C中,您实际上被迫在不透明库函数中动态分配它们。不可能在本地隐式声明不透明对象。这会对效率产生负面影响,并经常迫使客户端实施其他资源管理(即,记住在不再需要该对象时将其释放)。公开不透明对象的确切大小(在这种情况下,通过函数)并依靠alloca来分配存储空间,这与您获得更有效且相当省心的本地声明非常接近。

如果不需要整个函数的生存期,则可以用VLA代替alloca,但是作者可能不希望/不能使用VLA。 (我想说,使用VLA甚至比模拟真正的本地声明还要近。)

通常,为了实现相同的技术,不透明的对象大小可能会在头文件中作为编译时常量公开。但是,使用函数的另一个好处是,如果此隔离库中的对象大小发生更改,则不必重新编译整个项目(如注释中的@R。)。


答案的先前版本(以下几点仍然适用,但显然是次要的):

它并不完全等效,因为alloca违反了基于作用域的生存期规则。 alloca版本的内存的生存期延长到函数的结尾,而本地对象的生存期仅延长到块的结尾。这可能是一件坏事,取决于您的使用方式可能是一件好事。

在类似

的情况下
some_type *ptr;

if (some condition)
{
  ...
  ptr = /* alloca one object */;
  ...
}
else
{
  ...
  ptr = /* alloca another object */;
  ...
}

语义上的差异可能至关重要。不管是您的情况-从您到目前为止所发表的内容中,我无法确定。

语义上的另一个不相关的区别是memset将对象的所有字节清零,而= { 0 }不能保证填充字节的清零。然后将该对象与某些基于二进制的API(例如发送到压缩的I / O流)一起使用可能很重要。