如何定义一个自带数据区的结构体:三种数据结构体的比较

先看如下三个结构体的定义

这三个结构体的前三个成员都相同,前两个成员只是为了充个数,从而让我们定义的struct看上去真的像个结构体,一个是char类型,一个是int类型。最后一个也是int类型,iDataLen用于记录结构体自带数据的长度,pData指向的就是我们“认为”的数据区。

// 结构体1
typedef struct data_node1{
	char	cDummy;			
	int	iDummy;
	int	iDataLen;
	char*	pData;
}DATA_NODE1;
// 结构体2
typedef struct data_node2{
	char	cDummy;
	int	iDummy;
	int	iDataLen;
	char	pData[1];
}DATA_NODE2;
// 结构体3
typedef struct data_node3{
	char	cDummy;
	int	iDummy;
	int	iDataLen;
	char*	data(){
		return (char*)(this+1);
	}
}DATA_NODE3;

再写代码打印三个数据结构的信息

首先显示结构体的大小,前两个结构体是16字节,最后一个结构体是12字节,这个好理解,最后一个结构体中缺少一个成员变量。
说明一下:cDummy虽然是一个char类型,但由于结构体按照最大成员变量的size进行对齐,即使cDummy只需要个单室套,但计算机还是给它分了个三居室。
打个比方:如果你和吴亦凡在同一个struct中,那么你的size也会和“吴签”对齐的,计算机的世界就是这么平等。
在该函数中我们开辟三个256字节的内存块,并让其分别指向三个结构体,从而观察pData到底指向哪里。

#define INT_DATA_SIZE	256
void TestStruct()
{
	// 获取结构体的大小
	int iDNSize1 = sizeof(DATA_NODE1);
	int iDNSize2 = sizeof(DATA_NODE2);
	int iDNSize3 = sizeof(DATA_NODE3);

	printf("sizeof(DATA_NODE1) = %d\r\n", iDNSize1);
	printf("sizeof(DATA_NODE2) = %d\r\n", iDNSize2);
	printf("sizeof(DATA_NODE3) = %d\r\n", iDNSize3);

	// 分配三块内存,并初始化为0
	char* pData1 = (char*)malloc(INT_DATA_SIZE);
	memset(pData1, 0, INT_DATA_SIZE);
	char* pData2 = (char*)malloc(INT_DATA_SIZE);
	memset(pData2, 0, INT_DATA_SIZE);
	char* pData3 = (char*)malloc(INT_DATA_SIZE);
	memset(pData3, 0, INT_DATA_SIZE);

	// 将三块内存指向对应的结构体
	DATA_NODE1* pDN1 = (DATA_NODE1*)pData1;
	DATA_NODE2* pDN2 = (DATA_NODE2*)pData2;
	DATA_NODE3* pDN3 = (DATA_NODE3*)pData3;

	// 打印结构体1的数据
	
	printf("DATA_NODE1       : address = 0x%08x\r\n", pDN1);
	printf("  pDN1->cDummy   : address = 0x%08x, value = %d\r\n", &pDN1->cDummy, pDN1->cDummy);
	printf("  pDN1->iDummy   : address = 0x%08x, value = %d\r\n", &pDN1->iDummy, pDN1->iDummy); 
	printf("  pDN1->iDataLen : address = 0x%08x, value = %d\r\n", &pDN1->iDataLen, pDN1->iDataLen);
	printf("  pDN1->pData    : address = 0x%08x, poiter address = 0x%08x\r\n\r\n", &(pDN1->pData), pDN1->pData);
		

	// 打印结构体2的数据
	int iSizeStruct2 = pDN2->pData - (char*)pDN2;
	pDN2->iDataLen = INT_DATA_SIZE - iSizeStruct2;
	printf("DATA_NODE2       : address = 0x%08x\r\n", pDN2);
	printf("  pDN2->cDummy   : address = 0x%08x, value = %d\r\n", &pDN2->cDummy, pDN2->cDummy);
	printf("  pDN2->iDummy   : address = 0x%08x, value = %d\r\n", &pDN2->iDummy, pDN2->iDummy); 
	printf("  pDN2->iDataLen : address = 0x%08x, value = %d\r\n", &pDN2->iDataLen, pDN2->iDataLen);
	printf("  pDN2->pData    : address = 0x%08x, poiter address = 0x%08x\r\n\r\n", &(pDN2->pData), pDN2->pData);

	// 打印结构体3的数据
	int iSizeStruct3 = pDN3->data() - (char*)pDN3;
	pDN3->iDataLen = INT_DATA_SIZE - iSizeStruct3;
	printf("DATA_NODE3       : address = 0x%0x\r\n", pDN3);
	printf("  pDN3->cDummy   : address = 0x%0x, value = %d\r\n", &pDN3->cDummy, pDN3->cDummy);
	printf("  pDN3->iDummy   : address = 0x%0x, value = %d\r\n", &pDN3->iDummy, pDN3->iDummy); 
	printf("  pDN3->iDataLen : address = 0x%0x, value = %d\r\n", &pDN3->iDataLen, pDN3->iDataLen);
	printf("  pDN3->data()   : address = 0x%0x\r\n\r\n", pDN3->data());

	free(pData1);
	free(pData2);
	free(pData3);

}

运行结果如图:

在这里插入图片描述

最后看三个结构体在内存中的显示

为了直观表达结构体的内存,我们假设三个结构体初始地址均为0x10000000。

结构体1
在这里插入图片描述
结构体2
在这里插入图片描述
结构体3
在这里插入图片描述

显然,后两种方式可以实现数据区与结构体有机的结合在一起。那么这种定义的应用场景在哪呢?就举一个IP数据报文的例子吧。
在这里插入图片描述