c语言中的_attribute_的意义

本文介绍了数据对齐问题及其三种常见解决方法:手动对齐、使用#pragampack(n)和__attribute__((packed))。文章还详细解释了__attribute__((packed))的使用规则和语法。

我们在进行定义数据结构计算数据结构大小的时候,或者进行网络通讯的socket发送数据的时候,都会遇到一个共同的问题:数据对齐问题。

这个问题是硬件为提高访问数据的效率,引出的问题,这里就不具体说这样为什么可以提高数据的访问效率,有兴趣的人,网上都有。

既然这个问题是实实在在存在的,并且软件发展了这么多年,也肯定有破解之道,下面就简单的介绍常见的3种方法:

1. 手动对齐,根据自己定义的数据结构,然后根据大小,按照一定的规律去排兵布阵,就可以让数据结构紧凑,尽量少的出现内存空隙。

这种方法实际上就是要求我们有一个好的编程习惯,这样可以提高我们代码的整洁性,也可以节省内存空间

2. 使用#pragam pack(n) 对齐数据结构

这条预处理指令中的n就是按照那个字节进行对齐,n=1~4 并且必须是2的倍数

当n=4的时候,就是我们默认的数据结构对齐方式

当n=1的时候,也就是最节省空间的方法

以前受硬件条件的限制,我们能减少内存的占用就尽量少的占用内存,才会这样去做,不过现在的存储芯片,动辄上G,甚至上T,比以前的K级别的芯片容量打多了。

3. 使用 __attribute__ ((packed)) ,让编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,这样子两边都需要使用 __attribute__ ((packed))取消优化对齐,就不会出现对齐的错位现象。

这种方式与上边的第二种方式是相同的


针对这个问题,个人觉得已经没有什么好研究的了,存在就存在,我们的硬件太大了,毕竟不是新中国刚成立时期,却内存。如果确实想了解一下或者有强迫症的人,可以继续看下边关于attribute的一些使用规则,语法。


关于attribute的使用规则 来源于网上:

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中的实现,你一定会注意到下面的语句:

  1. typedef struct {
  2.     double x;
  3.     double y;
  4. } __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进行相应的约束。

在 C 语言中,`__reserve` 并不是一个标准的关键字或内置函数。然而,在特定的上下文中,它可能被某些编译器或库实现作为扩展功能引入。以下是关于 `__reserve` 的一些潜在解释以及相关内容: ### 可能的意义 1. **内存预留** 在某些嵌入式系统或者操作系统开发环境中,`__reserve` 可能用于指示编译器或链接器为某个资源(如全局变量、堆栈或其他特殊用途的数据结构)保留一段固定的内存区域。这种行为类似于 `_Alignas` 或其他内存分配控制机制[^1]。 2. **自定义宏或函数** 如果项目中有类似的命名约定,则可能是开发者为了某种目的而创建的一个宏或函数。例如: ```c #define __reserve(x) malloc(x) ``` 这种情况下,具体含义取决于项目的实际定义。 3. **与存储类修饰符相关联** 类似于 `__attribute__((aligned(16)))`,`__reserve` 可能是一种特殊的存储类修饰符,用于调整变量的行为或布局方式。这通常是编译器特有的扩展特性。 --- ### 示例代码 假设我们正在讨论的是一个假想的功能,下面是一些可能的用法示例: #### 示例 1:作为内存预留工具 如果 `__reserve` 是一种用于显式请求内存的方式,那么它的使用可能会如下所示: ```c void* buffer = __reserve(1024); // 假设该函数会分配并返回一块大小为1024字节的内存 if (buffer != NULL) { memset(buffer, 0, 1024); } ``` #### 示例 2:作为一种编译期指令 如果是编译器支持的一种特殊语法形式,它可以像这样工作: ```c char data[1024] __reserve; // 表明此数组需要特别处理,比如预加载到缓存中 ``` 需要注意的是,上述例子仅是为了展示可能性,并不代表任何真实的标准或实现。 --- ### 关键点总结 - 如果提到的具体名称确实存在但未广泛记录,则很可能是某款专用软件框架内的局部概念。 - 对于非标准化的语言特性和API文档查询时应优先考虑查阅对应平台的技术手册或是源码注释部分来获取权威解答[^5]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值