如何定義一個自帶資料區的結構體:三種資料結構體的比較

一隻會鏟史的貓發表於2021-07-22

先看如下三個結構體的定義

這三個結構體的前三個成員都相同,前兩個成員只是為了充個數,從而讓我們定義的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資料包文的例子吧。
在這裡插入圖片描述

相關文章