简体   繁体   English

C 中的“压缩”结构是什么?

[英]What is a "packed" structure in C?

I am going though some C code written for the Microchip C30 compiler and I often see structs defined as follows:我正在查看为 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;

What does packed mean?打包是什么意思?

When structures are defined, the compiler is allowed to add paddings (spaces without actual data) so that members fall in address boundaries that are easier to access for the CPU. 定义结构时,允许编译器添加填充(没有实际数据的空格),以便成员落入更容易访问CPU的地址边界。

For example, on a 32-bit CPU, 32-bit members should start at addresses that are multiple of 4 bytes in order to be efficiently accessed (read and written). 例如,在32位CPU上,32位成员应从4个字节的多个地址开始,以便有效地访问(读取和写入)。 The following structure definition adds a 16-bit padding between both members, so that the second member falls in a proper address boundary: 以下结构定义在两个成员之间添加了一个16位填充,以便第二个成员落在适当的地址边界:

struct S {
    int16_t member1;
    int32_t member2;
};

The structure in memory of the above structure in a 32-bit architecture is ( ~ = padding): 在32位架构中上述结构的存储器结构是( = padding):

+---------+---------+
| m1 |~~~~|   m2    |
+---------+---------+

When a structure is packed, these paddings are not inserted. 当打包结构时,不插入这些填充。 The compiler has to generate more code (which runs slower) to extract the non-aligned data members, and also to write to them. 编译器必须生成更多代码(运行速度较慢)以提取未对齐的数据成员,并写入它们。

The same structure, when packed, will appear in memory as something like: 打包时,相同的结构将在内存中显示为:

+---------+---------+
| m1 |   m2    |~~~~
+---------+---------+

It instructs the compiler to not add any padding between members of the struct . 它指示编译器不在struct成员之间添加任何填充。

See, for example, this page . 例如,请参阅此页面

_attribute__((__packed__))表示(最有可能)“不插入任何填充以使事情更快”,也可能意味着“不插入任何对齐以保持对齐”。

Let me explain the concept of padding in structures and then packed structures by taking an example. 让我通过一个例子解释结构填充的概念,然后填充结构。

And then let us see why packing is required. 然后让我们看看为什么需要包装。

Padding: 填充:

struct eg_struct
{
           unsigned char abc;
           unsigned int  xyz;
}

When the structure is declared as above on a 16 bit architecture, the variable abc would be assigned some address. 当在16位架构上如上所述声明结构时,将为变量abc分配一些地址。 The next address is not assigned to variable xyz , instead one extra byte is added, and then the next address would be assigned to the variable xyz . 下一个地址未分配给变量xyz ,而是添加一个额外字节,然后将下一个地址分配给变量xyz

In the end, the structure looks something like below: 最后,结构如下所示:

struct eg_struct
{
           unsigned char abc;
           unsigned char paddedbytes[1];
           unsigned int  xyz;
}

Padding makes addresses of member variables easily accessible to the microcontroller. 填充使微控制器可以轻松访问成员变量的地址。 The disadvantage is extra unnecessary bytes that come into the picture. 缺点是进入图片的额外不必要的字节。

Packing: 填料:

If same structure is declared using the attribute “ packed ”, the extra byte will not be added after the variable abc . 如果使用属性“ packed ”声明相同的结构,则在变量abc之后不会添加额外的字节。

Let me give one example where packing is needed: 让我举一个需要打包的例子:

Consider a microcontroller interfaced with an EEPROM where some structure is being stored. 考虑一个与EEPROM接口的微控制器,其中存储了一些结构。

Imagine a function writing to the EEPROM would look as below: 想象一下,写入EEPROM的函数如下所示:

Write_EEPROM(EEPROM address, Ram address, Byte count);

Now if packing is not done, the extra padded bytes would occupy space in the EEPROM, which is of no use. 现在如果没有完成打包,额外的填充字节将占用EEPROM中的空间,这是没有用的。

One thing that has not been explicitly called out is that packing usually is done to match predefined field structures. 尚未明确指出的一件事是通常进行打包以匹配预定义的字段结构。 For example, at the low level layer of a network interface, a series of bytes is exchanged between networked machines. 例如,在网络接口的低级层,在联网的机器之间交换一系列字节。 After the data is received, it will need to be mapped to a high level structure so that the data can be manipulated easily. 收到数据后,需要将其映射到高级结构,以便可以轻松地操作数据。 This is when no-padding is usually necessary, so that the structure directly maps to the bytes. 这是通常需要无填充的时候,因此结构直接映射到字节。

Network data interchange also involves byte endianness issue (ie almost all network data uses big endian format regardless the endianness of the source and destination machines). 网络数据交换还涉及字节字节序问题(即,无论源和目标机器的字节顺序如何,几乎所有网络数据都使用大端格式)。

Furthermore, some machines cannot access wide data in non-aligned address, for example, Cortex-M0 cores cannot access 32-bit data in non-32-bit aligned address, so care must be taken on writing networking code in such cases. 此外,某些机器无法访问非对齐地址中的宽数据,例如,Cortex-M0内核无法访问非32位对齐地址中的32位数据,因此在这种情况下必须注意编写网络代码。

When packed used during structure declaration, compiler will not add any padding to the members of the same structure.在结构声明期间使用 packed 时,编译器不会向同一结构的成员添加任何填充。 Below is the example code and output which is self explanatory.下面是示例代码和 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;
}

Compile编译

$ gcc structure_packed.c -o structure_packed $ gcc structure_packed.c -o structure_packed

Run|Output运行|输出

$./structure_packed $./structure_packed

size of struct A: 6, addr a: 0x7ffc6f177ed6, addr ai: 0x7ffc6f177ed7, addr ac: 0x7ffc6f177edb结构 A 的大小:6,地址 a:0x7ffc6f177ed6,地址 ai:0x7ffc6f177ed7,地址 ac:0x7ffc6f177edb

size of struct B: 12, addr b: 0x7ffc6f177edc, addr bi: 0x7ffc6f177ee0, addr bc: 0x7ffc6f177ee4结构 B 的大小:12,地址 b:0x7ffc6f177edc,地址 bi:0x7ffc6f177ee0,地址 bc:0x7ffc6f177ee4

addr of c: 0x7ffc6f177ed0 c 的地址:0x7ffc6f177ed0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM