`

__attribute__((packed))详解

 
阅读更多

转自 http://blog.csdn.net/primeprime/article/details/50646469

 

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__));

 

 

在每个系统上看下这个结构体的长度吧。
    内存对齐,往往是由编译器来做的,如果你使用的是gcc,可以在定义变量时,添加__attribute__,来决定是否使用内存对齐,或是内存对齐到几个字节,以上面的结构体为例:

 1)到4字节,同样可指定对齐到8字节。
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
} __attribute__ ((aligned(4))); 

2)不对齐,结构体的长度,就是各个变量长度的和
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
} __attribute__ ((packed));

 

 

 

 

 

跨平台时基于数据结构的网络通信

 
 
    网络通信通常分为基于数据结构的和基于流的。HTTP协议就是后者的一个例子。
    有时为了提高程序的处理速度和数据处理的方便,会使用基于数据结构的通信(不需要对流进行解析)。但是,当需要在多平台间进行通信时,基于数据结构的通信,往往要十分注意以下几个方面:
[1] 字节序
[2] 变量长度
[3] 内存对齐
    在常见的系统架构中(Linux X86,Windows),非单字节长度的变量类型,都是低字节在前,而在某些特定系统中,如Soalris Sparc平台,高字节在前。如果在发送数据前不进行处理,那么由Linux X86发向Soalris Sparc平台的数据值,势必会有极大的偏差,进而程序运行过程中无法出现预计的正常结果,更严重时,会导致段错误。
    对于此种情况,我们往往使用同一的字节序。在系统中,有ntohXXX(), htonXXX()等函数,负责将数据在网络字节序和本地字节序之间转换。虽然每种系统的本地字节序不同,但是对于所有系统来说,网络字节序是固定的-----高字节在前。所以,可以以网络字节序为通信的标准,发送前,数据都转换为网络字节序。
    转换的过程,也建议使用ntohXXX(), htonXXX()等标准函数,这样代码可以轻松地在各平台间进行移植(像通信这种很少依赖系统API的代码,做成通用版本是不错的选择)。

    变量的长度,在不同的系统之间会有差别,如同是Linux2.6.18的平台,在64位系统中,指针的长度为8个字节,而在32位系统中,指针又是4个字节的长度---此处只是举个例子,很少有人会将指针作为数据发送出去。下面是我整理的在64位Linux系统和32位Linux系统中,几种常见C语言变量的长度:
                short    int    long    long long    ptr    time_t
32位           2         4       4             8               4        4
64位           2         4       8             8               8        8
    在定义通信用的结构体时,应该考虑使用定常的数据类型,如uint32_t,4字节的固定长度,并且这属于标准C库(C99),在各系统中都可使用。

    内存对齐的问题,也与系统是64位还是32位有关。如果你手头有32位和64位系统,不妨写个简单的程序测试一下,你就会看到同一个结构体,即便使用了定常的数据类型,在不同系统中的大小是不同的。对齐往往是以4字节或8字节为准的,只要你写的测试程序,变量所占空间没有对齐到4或8的倍数即可,举个简单的测试用的结构体的例子吧:
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
};
    在每个系统上看下这个结构体的长度吧。
    内存对齐,往往是由编译器来做的,如果你使用的是gcc,可以在定义变量时,添加__attribute__,来决定是否使用内存对齐,或是内存对齐到几个字节,以上面的结构体为例:
 1)到4字节,同样可指定对齐到8字节。
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
} __attribute__ ((aligned(4))); 

2)不对齐,结构体的长度,就是各个变量长度的和
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
} __attribute__ ((packed));

 

分享到:
评论

相关推荐

    嵌入式编程规范 字节对齐

    ### 嵌入式编程规范:字节对齐详解 #### 概述 在嵌入式系统开发过程中,为了提高程序运行效率以及内存利用效率,字节对齐(Byte Alignment)是一个非常重要的概念。字节对齐是指在计算机内存中,数据结构中的各个...

    C 语言字节对齐

    ### C语言字节对齐详解 #### 一、字节对齐的概念 字节对齐是计算机编程领域中一个重要的概念,特别是在C语言这样的低级语言中尤为重要。它指的是计算机如何在内存中组织数据,使得数据能高效地被处理器访问。 - *...

    ioctl() 函数输入输出应用实例.doc

    ### ioctl() 函数输入输出应用实例详解 #### 实验背景及意义 `ioctl()` 函数在 Linux 和其他类 Unix 操作系统中被广泛用于与设备驱动程序进行交互,特别是那些不支持标准输入输出操作(如读写)的设备。本文档通过...

    深入内存对齐的详解

    深入内存对齐的详解 内存对齐是计算机编程中一个非常重要的概念,它直接影响着程序的性能和可读性。本文将深入探讨内存对齐,分析其原因和实现原理,并讨论相关的编程技术。 一、内存对齐的原因 在编程中,我们...

    驱动开发流程源码

    - `__attribute__((packed))`:确保结构体被紧密打包,避免不必要的内存填充,这对于硬件访问来说至关重要。 ##### 2.3 ioctl() 相关宏 - `_IO`、`_IOR`、`_IOW`、`_IORW`:这些宏用于定义 ioctl 命令的不同类型,...

    关于bluetooth的程序

    } __attribute__((packed)) inquiry_info; ``` - **字段说明**: - `bdaddr`: 设备地址。 - `pscan_rep_mode`: 页面扫描报告模式。 - `pscan_period_mode`: 页面扫描周期模式。 - `pscan_mode`: 页面扫描模式...

    c语言字节对齐

    ### C语言中的字节对齐详解 #### 一、引言 字节对齐是C语言编程中的一个重要概念,尤其在处理复杂数据结构时尤为重要。本文将深入探讨字节对齐的基本原理、目的以及如何在实际开发中进行合理配置。 #### 二、字节...

    BMP文件格式,用源代码进行说明

    ### BMP文件格式详解 BMP(Bitmap)是一种用于存储位图图像的标准文件格式,它能够支持单色和彩色图像,并且具有无损压缩的特点。在本文档中,我们将通过源代码的形式来详细介绍BMP文件的基本结构及其各部分的功能...

    详解Linux下读取位图的注意事项

    在结构体定义中,使用了__attribute__((packed))来避免编译器进行默认的内存对齐。这是因为在Windows中,位图数据通常是按照原始大小读取的,而在Linux中,为了提高内存访问效率,编译器可能会对结构体进行字节对齐...

    Crossbow产品无线通讯包格式

    负载数据的结构由用户自定义,如示例中的`XDataMsg`结构体,包含了加速度计和磁力计的数据,各字段采用`__attribute__((packed))`属性,确保数据紧密排列,减少存储空间。 **2. 特殊字符** - `7E`:起始和终止字符...

    C常见的问题集合(非常精彩)特别适用于想深入学习C语言或者做单片机、做嵌入式的同学

    ### C语言常见问题详解 #### 一、声明和初始化 **1.1 我如何决定使用哪种整数类型?** 在C语言中选择合适的整数类型对于确保程序的正确性和效率至关重要。通常,你可以根据所需的范围和精度来选择类型: - `...

    你必须知道的495个C语言问题

    - 结构的填充(padding)和对齐策略由编译器决定,可以使用`__attribute__((packed))`(GCC扩展)来关闭填充或调整对齐。 12. **运行时访问结构域**: - 在运行时访问结构域的名称,通常需要借助`offsetof`宏来...

    gcc3.4完全手册

    - **属性扩展**:通过使用特定属性来控制编译器的行为,例如`__attribute__((packed))`用于指定结构体成员紧密排列。 #### 六、C++语言扩展 对于C++,GCC3.4同样提供了一系列扩展功能: - **模板元编程**:支持复杂...

    嵌入式软件面试题整理.pdf

    `__attribute__((packed))` 用于关闭结构体成员之间的填充,避免不必要的对齐导致的额外内存消耗。 #### 交换分区 交换分区是硬盘上的一块区域,用于存储临时溢出的数据。当物理内存不足时,操作系统会将一部分内存...

    C语言常见问题集

    例如,在GCC中,可以使用`__attribute__((packed))`来禁用结构体的填充。这使得结构体更紧凑,但可能会影响性能。 **2.11 为什么`sizeof`返回的值大于结构的期望值,是不是尾部有填充?** 是的,`sizeof`返回的值...

Global site tag (gtag.js) - Google Analytics