簡體   English   中英

C 中的“壓縮”結構是什么?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM