C语言结构体中__packed 和位段的理解!

本文深入解析了C语言中的__packed属性和位段(bitfield)的概念。__packed用于控制结构体成员的字节对齐,有助于节省内存空间,尤其是在嵌入式系统中。位段则允许开发者在结构体中以位为单位定义成员,实现更精细的空间管理。文章通过实例解释了两者的工作原理和应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                          C语言中__packed 和位段的理解

一:__packed 

typedef __packed struct

struct常用在数据结构中。而struct的字节对齐方式对于嵌入式底层的程序员来讲是必须掌握的。现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数 据。显然在读取效率上下降很多。

C/C++语言中struct结构体定义中__packed的作用是什么?
例如代码为:

typedef struct __packed test_s
{
   int i;
   float f;
   double d;
   char c;
}test_t;


(1)__packed是字节对齐的意思。比如说int float double char它的总大小是4 + 4 + 8 + 1 = 17,但如果不用__packed的话,系统将以默认的方式对齐(假设是4字节),那么它占4 + 4 + 8 + 4 = 20;(不足4字节以4字节补齐)。
(2)在VS2008上述方法不能用了,如果想设置对齐方式,只要选择工程属性->配置属性->C/C++->代码生成就能设置,它的选项有1、2、4、8、16。在GCC下,可以在加上#pragma pack(4) 4字节对齐的意思,其它同理。

#pragma pack (1) /*指定按1字节对齐*/
#pragma pack () /*取消指定对齐,恢复缺省对齐*/

__packed是进行一字节对齐。使用_packed一般会以降低运行性能为代价,由于大多数cpu处理数据在合适的字节边界数的情况下会更有效,packed的使用会破坏这种自然的边界数。

二:位段

struct packed-data

{
  unsigned a:2;

  unsigned b:6;

  unsigned c:4;

  unsigned d:4;

  int i;

}data;

其中冒号表示啥意思?

C语言中,这叫 “位段”,C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”( bit field) 。利用位段能够用较少的位数存储数据。

冒号出现在struct结构当中表示只占用8位中的n位。也就是说,假如有如下代码:

unsigned  a1:1;

unsigned a2:2;

a1变量的范围为 0 1 ,a2的范围就是 0,1,2,3

<think>好的,用户想了解C或C++中的__packed关键字的含义用法。首先,我需要确认__packed是否是标准C/C++的一部分。根据我的知识,CC++的标准中没有这个关键字,所以它可能是编译器特定的扩展。 接下来,我应该回忆哪些编译器使用了__packed。常见的编译器如GCC、Clang、MSVC等,可能各自有不同的实现。比如在GCC中,通常使用__attribute__((packed))来实现结构体的紧凑排列,而__packed可能是一些其他编译器或嵌入式系统编译器如ARM Compiler(Keil)的关键字。 需要解释__packed的作用,即告诉编译器不要对结构体或联合体的成员进行内存对齐填充,从而节省内存空间,但可能导致访问效率降低。同时,需要注意使用这个关键字可能带来的问题,比如未对齐内存访问在某些架构上会导致错误或性能下降。 用户可能在使用嵌入式系统开发时遇到这个关键字,特别是在处理硬件寄存器或网络协议时需要精确控制内存布局。因此,实际应用场景示例代码会很有帮助。比如,展示一个结构体使用__packed前后的内存布局变化。 另外,需要提到不同编译器的语法差异,比如GCC使用__attribute__((packed)),而ARM Compiler使用__packed,MSVC可能有#pragma pack。这有助于用户根据自己使用的编译器选择合适的语法。 还要注意潜在的问题,比如跨平台移植时的兼容性问题,以及性能影响。这些都是在使用__packed时需要考虑的因素。 最后,生成相关问题,帮助用户进一步理解相关概念,如内存对齐、编译器扩展等。</think>### `__packed`关键字的含义与用法 `__packed`是某些C/C++编译器提供的**非标准扩展关键字**,主要用于控制结构体或联合体的内存对齐方式。它指示编译器不要对成员进行内存对齐填充,从而以节省内存空间为代价,换取数据在内存中的紧凑存储。 #### 核心作用 1. **消除内存对齐填充** 默认情况下,编译器会按照成员类型的大小自动插入填充字节以实现对齐(例如将4字节的`int`对齐到4的倍数地址)。使用`__packed`后,所有成员紧密排列,例如: ```c struct __packed SensorData { char id; int value; }; ``` 该结构体大小从默认的8字节(`char`占1字节 + 3填充字节 + `int`占4字节)变为5字节。 2. **硬件寄存器/网络协议解析** 在与硬件交互或解析二进制协议时,需确保数据布局与物理内存/协议格式完全一致[^1]。 #### 编译器支持差异 | 编译器 | 语法形式 | 示例 | |-----------------|----------------------------|--------------------------| | ARM Compiler | `__packed`关键字 | `struct __packed {...}` | | GCC/Clang | `__attribute__((packed))` | `struct __attribute__((packed)) {...}` | | MSVC | `#pragma pack(1)` | `#pragma pack(push,1)`<br>`struct {...}`<br>`#pragma pack(pop)` | #### 注意事项 1. **性能损失** 未对齐的内存访问在部分架构(如ARMv5)上会导致错误,而在x86等架构上则可能降低访问速度。例如: ```c __packed int* ptr = (__packed int*)0x1001; // 地址0x1001未按4字节对齐 int value = *ptr; // 在ARMv5上触发硬件异常 ``` 2. **可移植性** 使用该关键字的代码难以直接跨编译器移植,需通过宏定义适配不同编译器: ```c #ifdef __GNUC__ #define PACKED __attribute__((packed)) #elif defined(__ARMCC_VERSION) #define PACKED __packed #endif struct PACKED NetworkPacket {...}; ``` 3. **类型限制** 部分编译器禁止对含位域或复杂类型的结构体使用`__packed`。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魏波.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值