简体   繁体   English

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

[英]How to malloc a struct that contains a variable length array?

The CoreAudio framework uses a struct that is declared like this: CoreAudio框架使用如下声明的结构:

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

As far as I can tell, this is basically a variable length collection of AudioBuffer structs. 据我所知,这基本上是一个可变长度的AudioBuffer结构集合。 What is the 'correct' way to malloc such a struct? malloc这样一个结构的'正确'方法是什么?

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

Would this work? 这会有用吗?

I've seen all kinds of examples around the internet, like 我在互联网上看过各种各样的例子,比如

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

or 要么

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

That's not a variable length array; 那不是一个可变长度数组; it's a 'struct hack'. 这是一个'结构黑客'。 The standard (since C99) technique uses a 'flexible array member', which would look this: 标准(自C99)技术使用“灵活的阵列成员”,看起来如下:

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

One of the advantages of the FAM is that your questions are 'irrelevant'; FAM的一个优点是你的问题“无关紧要”; the correct way to allocate the space for numBuffer elements in the mBuffers array is: 正确的方式分配用于空间numBuffer中的元素mBuffers阵列是:

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

To answer your question, in practice both the malloc() and the calloc() will allocate at least enough space for the job, but nothing in any C standard guarantees that the code will work. 要回答你的问题,实际上malloc()calloc()都会为作业分配至少足够的空间,但任何C标准都没有保证代码能够正常工作。 Having said that, compiler writers know that the idiom is used and usually won't go out of their way to break it. 话虽如此,编译器编写者知道使用了这个习惯用法,并且通常不会破坏它。

Unless space is incredibly tight, it might be simplest to use the same expression as would be used with a FAM; 除非空间非常紧张,否则使用与FAM一样的表达式可能是最简单的; at worst, you have a little more space allocated than you absolutely need allocated. 在最坏的情况下,你分配的空间比你绝对需要的多一些。 It will continue to work when you upgrade the code to use a FAM. 升级代码以使用FAM时,它将继续工作。 The expression used in the calloc() version would also work with a FAM member; calloc()版本中使用的表达式也适用于FAM成员; the expression used in the malloc() version would suddenly be allocating too little space. malloc()版本中使用的表达式会突然分配太少的空间。

Work out how much memory you need and malloc that amount. 计算出你需要多少内存和malloc。 For example if you want 9 more AudioBuffers then 例如,如果你想要另外9个AudioBuffers

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

This entire construct is non-portable by the way (the behaviour is undefined if they access beyond the bound of mBuffers , which is 1), but it used to be reasonably common. 顺便说一下,整个结构是不可移植的(如果它们超出mBuffers范围访问,则行为是未定义的,这是1),但它曾经相当常见。

Note that you should not cast the value returned by malloc . 请注意,您不应该转换malloc返回的值。 There's no benefit to be gained by doing so, but there is harm that can be done. 这样做没有任何好处,但可以做到伤害。

There is a standard construct which is similar; 有一个类似的标准结构; if you remove the 1 from the definition of AudioBufferList (and malloc one more unit). 如果你从AudioBufferList的定义中删除1 (和malloc一个单位)。 This is called "flexible array member". 这称为“灵活阵列成员”。

The preferred way to do this is to use the Apple-provided CAAudioBufferList::Create function from CAAudioBufferList.cpp in the Core Audio Utility Classes. 执行此操作的首选方法是使用Core Audio Utility Classes中CAAudioBufferList.cpp中Apple提供的CAAudioBufferList::Create函数。 You can download the sources here: 你可以在这里下载资源:

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

Here is their implementation: 这是他们的实施:

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM