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