在阅读代码的时候发现,发现有的结构体末尾为附加一个0长度或者1长度的数组。其实这是一个小技巧,用这种方法可以实现变长结构体。变长结构体通常在网络通信中的报文头中比较常见。
struct Extra
{
int m_ext;
};
struct Header
{
int m_data;
int m_size;
char extra[0];
};
如上所示,struct Header的最后一个字段是长度为零的char类型数组。这个数组有什么用呢?实际上它被用来表示一个地址,这个地址指向Header结构体的末尾。有了这个指向结构体末尾的地址,我们就可以在这个地址上紧接着Header结构体放一些不定长度的附加信息。像下面的例子一样:
int alloc_size = sizeof(struct Header) + sizeof(struct Extra) * 5;
struct Header* pHeader = (struct Header*)malloc(alloc_size);
pHeader->m_data = 1;
pHeader->m_size = alloc_size;
//紧接着结构体放置附加字段,此处附加字段为5个struct Extra
struct Extra* pExtra = (struct Extra*)(pHeader->extra);
for (int i = 0; i < 5; ++i)
{
struct Extra* pCurrExtra = pExtra + i;
pCurrExtra->m_ext = i + 1;
}
由于有的编译器不支持0长度数组,所以这种情况下也可以用1长度数组:char extra[1],只不过这样整个Header结构体增加了1字节大小(不考虑内存对齐)。这个数组的类型也不一定非得是char,在我们的例子中,也可以是struct Extra[0]。
当时非常纳闷的一点是,数组的长度只有0或者1,那我们访问的时候不会溢出吗?其实溢出或者不溢出不在于数组的长度,而在于我们的指针所访问的地址是否是合法地址,比如我们的例子中pExtra + 2并不会溢出,因为pExtra+2所指的地址是我们自己分配的合法地址。