_attribute_((packed))

本文深入解析GCC中的packed属性,解释其作用、语法及使用场景,包括如何通过packed属性减小对象占用空间,以及其与连接器的关系。
_attribute_((packed))

1. __attribute__ ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有的语法。这个功能是跟操作系统没关系,跟编译器有关,gcc编译器不是紧凑模式的,我在windows下,用vc的编译器也不是紧凑的,用tc的编译器就是紧凑的。例如:

在TC下:struct my{ char ch; int a;} sizeof(int)=2;sizeof(my)=3;(紧凑模式)

在GCC下:struct my{ char ch; int a;} sizeof(int)=4;sizeof(my)=8;(非紧凑模式)

在GCC下:struct my{ char ch; int a;}__attrubte__ ((packed)) sizeof(int)=4;sizeof(my)=5

2. __attribute__关键字主要是用来在函数或数据声明中设置其属性。给函数赋给属性的主要目的在于让编译器进行优化。函数声明中的__attribute__((noreturn)),就是告诉编译器这个函数不会返回给调用者,以便编译器在优化时去掉不必要的函数返回代码。

GNU C的一大特色就是__attribute__机制。__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。

__attribute__书写特征是:__attribute__前后都有两个下划线,并且后面会紧跟一对括弧,括弧里面是相应的__attribute__参数。

__attribute__语法格式为:

__attribute__ ((attribute-list))

其位置约束:放于声明的尾部“;”之前。

函数属性(Function Attribute):函数属性可以帮助开发者把一些特性添加到函数声明中,从而可以使编译器在错误检查方面的功能更强大。__attribute__机制也很容易同非GNU应用程序做到兼容之功效。

GNU CC需要使用 –Wall编译器来击活该功能,这是控制警告信息的一个很好的方式。

packed属性:使用该属性可以使得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐。

如果你看过GPSR协议在TinyOS中的实现,你一定会注意到下面的语句:
typedef struct {
    double x;
    double y;
} __attribute__((packed)) position_t;

开始我们还可以理解,不久是定义一个结构体嘛!不过看到后面的语句,你可能就会一头雾水了,’ __attribute__((packed))’是什么东西?有什么作用?一连串的疑问马上就会从你脑袋里冒出来。虽然这个对理解整个程序没有什么影响,但我不想让这些疑问一直呆在我的脑子里,负担太重。省得以后念念不忘,而且也许有一天可以用的上呢。搞清楚这个问题吧!

GNU C的一大特色(却不被初学者所知)就是__attribute__机制。__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。
__attribute__语法格式为:
__attribute__ ((attribute-list))

其位置约束为:放于声明的尾部“;”之前。

packed是类型属性(Type Attribute)的一个参数,使用packed可以减小对象占用的空间。需要注意的是,attribute属性的效力与你的连接器也有关,如果你的连接器最大只支持16字节对齐,那么你此时定义32字节对齐也是无济于事的。

使用该属性对struct或者union类型进行定义,设定其类型的每一个变量的内存约束。当用在enum类型定义时,暗示了应该使用最小完整的类型(it indicates that the smallest integral type should be used)。

下面的例子中,my-packed-struct类型的变量数组中的值会紧凑在一起,但内部的成员变量s不会被“pack”,如果希望内部的成员变量也被packed的话,my-unpacked-struct也需要使用packed进行相应的约束。
struct my_unpacked_struct
{
     char c;
     int i;
};
          
struct my_packed_struct 
{
     char c;
     int i;
     struct my_unpacked_struct s;
}__attribute__ ((__packed__));


__attribute__机制的详细介绍请参考:

http://www.unixwiz.net/techtips/gnu-c-attributes.html

<think> 我们正在讨论C语言中的预处理指令和GCC特性。用户的问题是关于`#define GNU_PACKED __attribute__ ((packed))`的含义,以及`__attribute__`是否为函数。 首先,我们来解释`#define GNU_PACKED __attribute__ ((packed))`: - 这是一个宏定义,将`GNU_PACKED`定义为`__attribute__ ((packed))`。 - `__attribute__`是GCC编译器提供的一种特殊语法,用于向编译器提供关于函数、变量或类型的额外信息,以控制编译器的行为(如优化、内存布局等)。 - `packed`属性用于结构体或联合体,告诉编译器尽可能紧凑地排列成员,即取消成员之间的内存对齐(padding),以减少内存占用。 例如: ```c struct my_struct { char a; int b; char c; } __attribute__ ((packed)); ``` 这个结构体通常(没有packed)可能会在`char a`后面插入3个字节的填充(以使`int b`对齐到4字节边界),然后`char c`后面可能再插入3个字节的填充(以使整个结构体大小为对齐后的整数倍)。但使用`packed`后,编译器会取消所有填充,结构体的大小为`1+4+1=6`字节。 现在,关于`__attribute__`是否为函数: - `__attribute__`不是函数,而是一个GCC的关键字(在Clang等其他编译器中也支持)。它用于指定属性,其语法为: `__attribute__ ((attribute-list))` 其中`attribute-list`是一个或多个用逗号分隔的属性,如`packed`, `noreturn`, `aligned`等。 用户提供的引用[2]中也说明了这一点:`__attribute__`用于函数声明(而不是定义),并且需要单独在声明中指定。例如: ```c void die(const char *format, ...) __attribute__((noreturn)) __attribute__((format(printf,1,2))); ``` 这里`noreturn`属性告诉编译器该函数不会返回(如调用exit),`format`属性用于检查格式化字符串参数。 所以,总结如下: 1. `#define GNU_PACKED __attribute__ ((packed))`定义了一个宏,用于为结构体或联合体指定紧凑的内存布局。 2. `__attribute__`不是函数,而是GCC的扩展语法,用于指定各种属性。 在回答中,我们会清晰地解释宏定义的作用和`__attribute__`的性质,并举例说明。 由于用户的问题与引用内容关系不大(引用[1]是一个构造函数的例子,引用[2]是关于`__attribute__`用于函数声明的例子),我们主要基于对宏和属性的理解回答,但可以提及引用[2]中关于`__attribute__`用于函数声明的说明来支持我们的观点。 最后,生成相关问题。 </think> ### `#define GNU_PACKED __attribute__ ((packed))` 的含义解析 #### 1. **宏定义的本质** `#define GNU_PACKED __attribute__ ((packed))` 是一个C/C++预处理宏指令: - 将标识符 `GNU_PACKED` 定义为 `__attribute__ ((packed))` - 在编译前,所有出现 `GNU_PACKED` 的地方都会被替换为 `__attribute__ ((packed))` - 例如: ```c struct data { char a; int b; } GNU_PACKED; // 展开为 __attribute__ ((packed)) ``` #### 2. **`__attribute__ ((packed))` 的作用** 这是GCC编译器的特有扩展语法: - **功能**:强制编译器取消结构体/联合体的内存对齐填充 - **场景**:当需要精确控制内存布局时(如网络协议、硬件寄存器映射) - **对比示例**: ```c struct without_packed { // 默认有填充字节 char c; // 1字节 int i; // 4字节(编译器插入3字节填充) }; // 总大小=8字节 struct with_packed { char c; int i; } __attribute__((packed)); // 总大小=5字节 ``` - **数学表示**:若结构体成员大小为 $\sum_{i=1}^{n} s_i$,使用packed后总大小严格等于 $\sum s_i$,无填充项。 #### 3. **`__attribute__` 是否为函数?** **不是函数**,而是编译器指令: - **语法性质**:GCC/Clang特有的编译器扩展属性 - **使用方式**: - 附加在声明后修饰类型(如结构体) - 或附加在函数原型后(如引用[^2]的 `noreturn` 示例) - **与函数本质区别**: - 不参与运行时计算 - 无返回值 - 仅在编译期指导编译器行为 ### 关键总结 | 组件 | 性质 | 作用 | |------|------|------| | `#define GNU_PACKED` | 宏替换 | 简化 `__attribute__((packed))` 的书写 | | `__attribute__` | 编译器指令 | 提供低级内存/行为控制 | | `packed` | 属性参数 | 禁用结构体对齐填充 | > 此机制常见于嵌入式系统和网络编程,例如定义符合硬件规范的协议头结构[^1]。 --- ### 相关问题 1. 如何在非GCC编译器(如MSVC)中实现类似`packed`的内存对齐控制? 2. `__attribute__((aligned(16))`与`packed`同时使用时会产生什么效果? 3. 过度使用`packed`属性可能导致哪些性能问题? 4. 如何检测结构体成员的真实内存偏移量来验证`packed`效果?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值