先看如下三個結構體的定義
這三個結構體的前三個成員都相同,前兩個成員只是為了充個數,從而讓我們定義的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資料包文的例子吧。