如何malloc包含可变长度数组的结构?

时间:2014-03-15 23:36:16

标签: c arrays struct malloc core-audio

CoreAudio框架使用如下声明的结构:

struct AudioBufferList
{
    UInt32      mNumberBuffers;
    AudioBuffer mBuffers[1]; // this is a variable length array of mNumberBuffers elements
};
typedef struct AudioBufferList  AudioBufferList;

据我所知,这基本上是AudioBuffer结构的可变长度集合。什么是正确的'这种结构的方法是malloc吗?

AudioBufferList *list = (AudioBufferList *)malloc(sizeof(AudioBufferList));

这会有用吗?

我已经在互联网上看过各种各样的例子,比如

calloc(1, offsetof(AudioBufferList, mBuffers) +
          (sizeof(AudioBuffer) * numBuffers))

malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer) * (numBuffers - 1))

3 个答案:

答案 0 :(得分:9)

这不是一个可变长度数组;这是一个'结构黑客'。标准(自C99)技术使用“灵活的阵列成员”,看起来如下:

struct AudioBufferList
{
    UInt32      mNumberBuffers;
    AudioBuffer mBuffers[]; // flexible array member
};

FAM的一个优点是你的问题“无关紧要”;为numBuffer数组中的mBuffers元素分配空间的正确方法是:

size_t n_bytes = sizeof(struct AudioBufferList) + numBuffer * sizeof(AudioBuffer);
struct AudioBufferList *bp = malloc(nbytes);

要回答您的问题,实际上malloc()calloc()都会为作业分配至少足够的空间,但任何C标准都没有保证代码能够正常工作。话虽如此,编译器编写者知道这个成语已被使用,并且通常不会破坏它。

除非空间非常紧张,否则使用与FAM一样的表达式可能是最简单的;在最坏的情况下,你分配的空间比你绝对需要的多一些。升级代码以使用FAM时,它将继续工作。 calloc()版本中使用的表达式也适用于FAM成员; malloc()版本中使用的表达式会突然分配太少的空间。

答案 1 :(得分:3)

计算出你需要多少内存和malloc那个数量。例如,如果你想要另外9个AudioBuffers那么

list = malloc( sizeof *list + 9 * sizeof list->mBuffers[0] );

顺便说一下,整个构造都是不可移植的(如果行为超出mBuffers的范围,则行为是未定义的,这是1),但它曾经相当普遍。

请注意,您不应转换malloc返回的值。这样做没有任何好处,但是可以做到伤害。

有一个类似的标准结构;如果从1的定义中删除AudioBufferList(并且再添加一个malloc)。这被称为"灵活的阵列成员"。

答案 2 :(得分:2)

执行此操作的首选方法是在Core Audio Utility Classes中使用Apple提供的来自CAAudioBufferList.cpp的CAAudioBufferList::Create函数。您可以在此处下载资源:

https://developer.apple.com/library/mac/samplecode/CoreAudioUtilityClasses/Introduction/Intro.html

以下是他们的实施:

AudioBufferList*    CAAudioBufferList::Create(UInt32 inNumberBuffers)
{
    UInt32 theSize = CalculateByteSize(inNumberBuffers);
    AudioBufferList* theAnswer = static_cast<AudioBufferList*>(calloc(1, theSize));
    if(theAnswer != NULL)
    {
        theAnswer->mNumberBuffers = inNumberBuffers;
    }
    return theAnswer;
}

void    CAAudioBufferList::Destroy(AudioBufferList* inBufferList)
{
    free(inBufferList);
}

UInt32  CAAudioBufferList::CalculateByteSize(UInt32 inNumberBuffers)
{
    UInt32 theSize = SizeOf32(AudioBufferList) - SizeOf32(AudioBuffer);
    theSize += inNumberBuffers * SizeOf32(AudioBuffer);
    return theSize;
}