我已经看到了循环缓冲区的以下实现:
http://en.wikipedia.org/wiki/Circular_buffer
/**< Buffer Size */
#define BUFFER_SIZE 10
#define NUM_OF_ELEMS (BUFFER_SIZE-1)
/**< Circular Buffer Types */
typedef unsigned char INT8U;
typedef INT8U KeyType;
typedef struct
{
INT8U writePointer; /**< write pointer */
INT8U readPointer; /**< read pointer */
INT8U size; /**< size of circular buffer */
KeyType keys[0]; /**< Element of circular buffer */
} CircularBuffer;
/**< Init Circular Buffer */
CircularBuffer* CircularBufferInit(CircularBuffer** pQue, int size)
{
int sz = size*sizeof(KeyType)+sizeof(CircularBuffer);
*pQue = (CircularBuffer*) malloc(sz);
if(*pQue)
{
printf("Init CircularBuffer: keys[%d] (%d)\n", size, sz);
(*pQue)->size=size;
(*pQue)->writePointer = 0;
(*pQue)->readPointer = 0;
}
return *pQue;
}
int main(int argc, char *argv[])
{
CircularBuffer* que;
KeyType a = 101;
int isEmpty, i;
CircularBufferInit(&que, BUFFER_SIZE);
...
}
以下是问题:
Q1&GT;为什么代码使用以下行来定义变量键?
KeyType keys[0]; /**< Element of circular buffer */
Q2&GT;为什么代码计算分配缓冲区的大小,如下所示:
int sz = size*sizeof(KeyType)+sizeof(CircularBuffer);
Q3&GT;为什么pQue指向一个大于CircularBuffer大小的缓冲区,但仍然可以 直接指它的成员?
(*pQue)->size=size;
(*pQue)->writePointer = 0;
(*pQue)->readPointer = 0;
答案 0 :(得分:2)
第一项只是指定struct中的元素使用数组语法,但实际上并未声明为任何大小的数组。
malloc分配循环缓冲区大小(占所有非关键字段)和关键字段(size * sizeof(KeyType))。请注意,键[0]实际上的大小为零,因此没有键字段被计算两次。
缓冲区实际上并不大于循环缓冲区的大小,分配(如上所述)是一次性分配,以便在一次传递中容纳循环缓冲区和控制元素(size,readPointer,writePointer)
这样做的全部原因是因为C没有检查你是否走出了数组的末尾。在一种强制数组边界的语言中,第一次尝试使用它时,你会得到类似于Java的ArrayOutOfBoundsException,因为要使用keys [0],你必须声明一个大小(至少)一个的键数组,像键[1]。
换句话说,在没有编码固定大小的情况下,优化缓冲区分配一次是一些C特定的黑客攻击。它起作用的原因是因为数组偏移严格实现为(基地址+索引* sizeof(数组类型))。
答案 1 :(得分:1)
int sz = size*sizeof(KeyType)+sizeof(CircularBuffer);
size =循环缓冲区中元素的数量
sizeof(KeyType)=单个KeyType元素的大小
(size * sizeof)=用于存储所有KeyType元素的总空间量
sizeof(CircularBuffer)=因为循环缓冲区存储的附加字段不是循环缓冲区元素
为什么代码使用以下行来定义变量键?
KeyType键[0]; / ** LT;循环缓冲区元素* /
我无法理解你的怀疑。这很常见。循环缓冲区用元素数组表示,其类型为KeyType。 如果你想知道为什么它使用KeyType而不是直接unsigned int那是因为:
答案 2 :(得分:1)
正在发生的事情是,在内存块的开始处有一个“头”结构,后面是可变数量的“细节”结构。这曾经是一种常见的做事方式,早在旧日;你可以通过调用malloc()来创建所有结构,这样对性能有好处。您可能也会经常使用文件处理代码或网络协议来查看此模式,您将获得可变大小的数据块,其精确大小在标头中给出。 (Excel BIFF格式和TCP
1:零长度数组曾经是在结构末尾指定可变长度数组的常用方法。
2:它为头部分配sizeof(CircularBuffer)字节,并为size * sizeof(KeyType)分配,以便可以有那么多KeyType。最终得到一个内存块,它同时包含标题和键。
3:没有指向你分配的内存块中的区域。如果它指向分配区域的OUTSIDE,那就不好了,但事实并非如此。
答案 3 :(得分:1)
此代码实现了一些有时称为“弹性数组”的东西。目标是在编译时不知道数组的大小时创建包含数组的结构。因此,结构定义为零大小的数组作为最后一个元素。分配时,将所需大小添加到malloc调用中。因为C保证malloc'd块是连续的,并且因为它不进行数组边界检查,所以可以将过去的0索引到附加内存中,并将其视为常规数组元素。
请注意,此技术仅在malloc结构时有效。如果它被声明为局部变量,则阵列将没有额外的空间。