如何定义一个自带数据区的结构体:三种数据结构体的比较
先看如下三个结构体的定义
这三个结构体的前三个成员都相同,前两个成员只是为了充个数,从而让我们定义的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数据报文的例子吧。