详解C语言结构体尾部:案例分析__attribute__((packed))

1、attribute

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

__attribute__语法格式为:

__attribute__ ((attribute-list))

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

2、GUN CC

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

函数属性(Function Attribute):函数属性可以帮助开发者把一些特性添加到函数声明中,从而可以使编译器在错误检查方面的功能更强大。

3、packed

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

如果你看过GPSR协议在TinyOS中的实现,你一定会注意到下面的语句:

typedef struct {
    double x;
    double y;
} __attribute__((packed)) position_t;

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

4、内存对齐

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

  1. 4字节同样可指定对齐到8字节。
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
} __attribute__ ((aligned(4))); 
  1. 不对齐,结构体的长度,就是各个变量长度的和
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
} __attribute__ ((packed));
 

5、为什么要用 “ attribute ((packed)) ” 定义结构体

通常定义一个U32 ,CPU 期望 这个 U32 地址是 DW 对齐的, 这样对CPU访问 mem bus 比较友好。

所以,当我们定义这样一个结构体:

struct test{
 
        char i,
 
        uint32 a
 
}

那么,编译器会默认在 i 和 a 之间插入 reserve,确保 a 的位置是 4 对齐的。sizeof(test) = 8.

它就等效于:

struct test{
 
        char i,
 
        char reserve[3],
 
        uint32 a
 
}

加入 “attribute ((packed))” 的效果,则在于避免编译器 “自作聪明”。 告诉编译器,我们这里不需要补全。

struct  __attribute__ ((__packed__)) test{
 
        char i,
 
        uint32 a
 
}

sizeof(test) = 5; 这会造成 a 地址不对齐,反而引入麻烦。

6、一个例子

attribute ((packed)) 对齐或者取消对齐实例,要注意摆放的位置,不然没办法跟编译器经常兼容性的执行项目。下面看看一个例子就了解了:

#include<stdio.h>
#include<stdlib.h>
 
typedef struct{
char a;
short b;
int c;
}__attribute__ ((packed)) sttest  ;
 
 
/*__attribute__ ((packed));*/
 
int main(void)
{
	char stsize;
	sttest stTest;
	void *addra,*addrb,*addrc;
       
        stsize =  sizeof(sttest);
	
	addra = &stTest.a;
	addrb = &stTest.b;
	addrc = &stTest.c;
	printf("stsize is %d\n",stsize);
	printf("a is %d\n",addra);
	printf("a is %d\n",addrb);
	printf("a is %d\n",addrc);
	return 0;
}

执行结果:

在这里插入图片描述
再来看一个例子:packed的作用是取消字节对齐

#include<stdio.h>
 
typedef struct {
 
    int i;  //4
    char a; //1
    char b; //1
    char c; //1
            //1
 
}Test1;
 
typedef struct {
 
    int i;  //4
    char a; //1
    char b; //1
    char c; //1
 
}__attribute__((packed))Test2;
 
typedef struct {
 
    int i;  //4
    char a; //1
    char b; //1
    char c; //1
 
}__attribute__((__packed__))Test3;
 
int
main(int argc, char *argv[])
{
 
    printf("Test1 = %d \r\n",sizeof(Test1));
    printf("Test2 = %d \r\n",sizeof(Test2));
    printf("Test3 = %d \r\n",sizeof(Test3));
 
    return 0;
}
/**输出结果:
Test1 = 8
Test2 = 7
Test3 = 7
*/
  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

源代码杀手

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

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

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

打赏作者

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

抵扣说明:

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

余额充值