struct中的数组和指针

#include "printf.h"

int main(int argc, char *argv[])
{
	struct TEST1
	{
		int len;
		char data[0];
	}test1;

	struct TEST2
	{
		int len;
		char *data;
	}test2;
	
	PRINTF_DEBUG("TEST1 size[%lu]", sizeof(test1));
	PRINTF_DEBUG("TEST2 size[%lu]", sizeof(test2));
	return 0;
}

在这里插入图片描述
这里可以看出来两点:
1.struct的内存对齐是按照成员最大的那一个来的
2.数组在struct中不占大小
重点说第2个,在linux内核代码中屡见不鲜! 这个用法主要用于变长buffer,test1的大小为4,结构体中的data[0]不占用任何空间,甚至是一个指针的空间都不占,data在这儿只是表示一个常量指针,这个特性是编译器来实现的,即在使用test1.data的时候,这个指针就是表示分配内存地址中的某块buffer,比如:

_test1 *test1 = malloc(sizeof (_test1) + data_len);
test1->len = data_len;
memcpy(test1->data, buffer, data_len);

对于这个用法,我们定义的结构体指针可以指向任意长度的内存buffer,这个技巧在变长buffer中使用起来相当方便。可能有朋友说,为什么不把最后的data直接定义为一个指针呢?这儿的差别是这样的,如果定义为一个指针,它需要占用4Bytes,并且在申请好内存后必须人为赋地址才可以使用。比较一下定义指针的用法:

_test2 test2 = malloc(sizeof (_test2));
test2.len = data_len;
test2->data = malloc(data_len);
memcpy(test2->data, buffer, data_len);
free(test2->data);
free(test2)

总结:
1.存储大小方面,test1的存储比test2要少,[0]的好处,即用指针的方式需要多开辟存储空间的。
2.数据连续存储方面,test2明显data是单独开辟的空间,与前面的len不在连续的存储区域,而test1的两个成员则在连续的存储空间下。
3.释放内存方面,test2的指针的方式,需要先释放data部分,才能释放指向结构体的指针变量,而test1可以直接释放。
结构体最后使用0或1的长度数组的原因,主要是为了方便的管理内存缓冲区,如果你直接使用指针而不使用数组,那么,你在分配内存缓冲区时,就必须分配结构体一次,然后再分配结构体内的指针一次,(而此时分配的内存已经与结构体的内存不连续了,所以要分别管理即申请和释放)。
而如果使用数组,那么只需要一次malloc就可以全部分配出来,反过来,释放时也是一样,使用数组,一次释放,使用指针,得先释放结构体内的指针,再释放结构体。还不能颠倒次序。
其实变长结构体就是分配一段连续的的内存,减少内存的碎片化,简化内存的管理。
4.变长结构体的应用,socket通信数据包的传输。这个用法在我们公司的很多网络协议处理的地方都这么使用。
最后GNUC下可以编译通过,所以你在使用vc++,那就不用尝试了,编译都无法通过!

你可能感兴趣的:(内存管理)