繁体   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