[英]What is a "packed" structure in C?
我正在查看為 Microchip C30 編譯器編寫的一些 C 代碼,我經常看到定義如下的結構:
typedef struct __attribute__((__packed__))
{
IP_ADDR MyIPAddr; // IP address
IP_ADDR MyMask; // Subnet mask
IP_ADDR MyGateway; // Default Gateway
// etc...
} APP_CONFIG;
打包是什么意思?
定義結構時,允許編譯器添加填充(沒有實際數據的空格),以便成員落入更容易訪問CPU的地址邊界。
例如,在32位CPU上,32位成員應從4個字節的多個地址開始,以便有效地訪問(讀取和寫入)。 以下結構定義在兩個成員之間添加了一個16位填充,以便第二個成員落在適當的地址邊界:
struct S {
int16_t member1;
int32_t member2;
};
在32位架構中上述結構的存儲器結構是( 〜 = padding):
+---------+---------+
| m1 |~~~~| m2 |
+---------+---------+
當打包結構時,不插入這些填充。 編譯器必須生成更多代碼(運行速度較慢)以提取未對齊的數據成員,並寫入它們。
打包時,相同的結構將在內存中顯示為:
+---------+---------+
| m1 | m2 |~~~~
+---------+---------+
它指示編譯器不在struct
成員之間添加任何填充。
例如,請參閱此頁面 。
_attribute__((__packed__))
表示(最有可能)“不插入任何填充以使事情更快”,也可能意味着“不插入任何對齊以保持對齊”。
讓我通過一個例子解釋結構填充的概念,然后填充結構。
然后讓我們看看為什么需要包裝。
填充:
struct eg_struct
{
unsigned char abc;
unsigned int xyz;
}
當在16位架構上如上所述聲明結構時,將為變量abc
分配一些地址。 下一個地址未分配給變量xyz
,而是添加一個額外字節,然后將下一個地址分配給變量xyz
。
最后,結構如下所示:
struct eg_struct
{
unsigned char abc;
unsigned char paddedbytes[1];
unsigned int xyz;
}
填充使微控制器可以輕松訪問成員變量的地址。 缺點是進入圖片的額外不必要的字節。
填料:
如果使用屬性“ packed
”聲明相同的結構,則在變量abc
之后不會添加額外的字節。
讓我舉一個需要打包的例子:
考慮一個與EEPROM接口的微控制器,其中存儲了一些結構。
想象一下,寫入EEPROM的函數如下所示:
Write_EEPROM(EEPROM address, Ram address, Byte count);
現在如果沒有完成打包,額外的填充字節將占用EEPROM中的空間,這是沒有用的。
尚未明確指出的一件事是通常進行打包以匹配預定義的字段結構。 例如,在網絡接口的低級層,在聯網的機器之間交換一系列字節。 收到數據后,需要將其映射到高級結構,以便可以輕松地操作數據。 這是通常需要無填充的時候,因此結構直接映射到字節。
網絡數據交換還涉及字節字節序問題(即,無論源和目標機器的字節順序如何,幾乎所有網絡數據都使用大端格式)。
此外,某些機器無法訪問非對齊地址中的寬數據,例如,Cortex-M0內核無法訪問非32位對齊地址中的32位數據,因此在這種情況下必須注意編寫網絡代碼。
在結構聲明期間使用 packed 時,編譯器不會向同一結構的成員添加任何填充。 下面是示例代碼和 output,這是不言自明的。
$ cat structure_packed.c
#include <stdio.h>
typedef struct __attribute__((__packed__))
{
char a;
int ai;
char ac;
}A;
struct B
{
char b;
int bi;
char bc;
};
int main()
{
A a;
struct B b;
int c;
printf("size of struct A: %lu, addr a: %p, addr ai: %p, addr ac: %p\n", sizeof(a), &(a.a), &(a.ai), &a.ac);
printf("size of struct B: %lu, addr b: %p, addr bi: %p, addr bc: %p\n", sizeof(b), &(b.b), &(b.bi), &b.bc);
printf("addr of c: %p\n", &c);
return 0;
}
編譯
$ gcc structure_packed.c -o structure_packed
運行|輸出
$./structure_packed
結構 A 的大小:6,地址 a:0x7ffc6f177ed6,地址 ai:0x7ffc6f177ed7,地址 ac:0x7ffc6f177edb
結構 B 的大小:12,地址 b:0x7ffc6f177edc,地址 bi:0x7ffc6f177ee0,地址 bc:0x7ffc6f177ee4
c 的地址:0x7ffc6f177ed0
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.