字节对齐

为什么要字节对齐,用意何在?

  如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐。比如在32cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的。需要字节对齐的根本原因在于CPU访问数据的效率问题。假设之前整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次内存,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。而如果变量在自然对齐位置上,则只要一次就可以取出数据。所以字节对齐可以提高效率。当然对齐的工作编译器会帮我自动完成。

字节对齐在结构体中比较常见,

struct stu{

   char sex;

   int length;

   char name[10];

};

一般GCC或者其他编译器默认结构体中所占内存最大的字节数对齐(例如上面结构体length最大占4个字节,所以结构体按照4字节对齐,如果int换成short则是按照2字节对齐,换成double则是按照8字节对齐,注意数组则是按照总体大小是否能被对齐大小整除,如果不能则填充直到能被整除),它会在sex后面跟name后面分别填充三个和两个字节使length和整个结构体对齐。于是我们sizeof(my_stu)会得到长度为20,而不是15

那么如何制定对齐的大小呢?

 struct stu{

   char sex;

   int length;

   char name[10];

}__attribute__ ((aligned (1))); 

GNU使用__attribute__选项来设置,理论上上面的结构体这样定义的话大小应该是15而不是20,但实际测试发现仍然是20(??),但是换成_attribute__ ((packed))或者下面所说的pack指令则起了作用使得变量或者结构体成员使用最小的对齐方式。(理论上_attribute__ ((packed))等价于__attribute__ ((aligned (1))))

也可以使用使用伪指令#pragma pack (n),使得C编译器将按照n个字节对齐。

然后在结尾处使用伪指令#pragma pack (),取消自定义字节对齐方式。

注意无论是哪种方法,对于结构体而言对齐大小都只针对1和偶数对齐有效,并且设置超过元素所占最大内存也会无效,例如在上面的结构体设置8字节对齐,但实际仍然还是4字节对齐。3字节对齐仍然还是4字节对齐。

注意:实际测试发现__attribute__ ((aligned (n)))这种表达式效果不是很好,例如同样设置2字节对齐,使用__attribute__ ((aligned (2)))后上面结构体大小仍然为20字节而使用pack则为预想的16字节。

既然编译器已经帮我完成了字节对齐的工作,那么我们为什么还要注意呢?其答案在与节约内存。

struct A {

    char b;

short c;

int a;

};

struct B {
    char b;
    int a;
    short c;
};

 

同样的成员变量,但是不同的写法,所占的内存不一样,结构体A大小为8个字节,而结构体B大小为12个字节。

所以针对字节对齐,我们在编程中如何考虑?

如果在编程的时候要考虑节约空间的话,那么我们只需要假定结构的首地址是0,然后各个变量按照上面的原则进行排列即可,基本的原则就是把结构中的变量按照类型大小从小到大声明,尽量减少中间的填补空间.还有一种就是为了以空间换取时间的效率,我们显示的进行填补空间进行对齐,比如:有一种使用空间换时间做法是显式的插入reserved成员:

             struct A{

               char a;

               char reserved[3];//使用空间换时间

               int b;

}

reserved成员对我们的程序没有什么意义,它只是起到填补空间以达到字节对齐的目的,当然即使不加这个成员通常编译器也会给我们自动填补对齐,我们自己加上它只是起到显式的提醒作用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中,结构体的字节对齐是为了优化内存访问速度和对齐要求而进行的一种对齐方式。结构体的字节对齐确保结构体中的成员按照一定的规则进行排列,以便于处理器高效地访问内存。 结构体的字节对齐规则通常由编译器根据特定的对齐选项和目标平台的要求来确定。在C语言中,可以使用`#pragma pack`指令或者编译器提供的特定选项来控制结构体的字节对齐方式。 默认情况下,大多数编译器会按照特定的对齐规则进行字节对齐。这些规则通常是根据基本数据类型的大小来确定的。例如,常见的对齐规则是按照4字节对齐(即结构体成员的偏移量必须是4的倍数)或者8字节对齐。 以下是一个示例,展示了如何使用`#pragma pack`指令来设置结构体的字节对齐方式: ```c #pragma pack(push, 1) // 以1字节对齐 struct MyStruct { char c; int i; double d; }; #pragma pack(pop) // 恢复默认的对齐方式 int main() { printf("sizeof(MyStruct) = %zu\n", sizeof(struct MyStruct)); return 0; } ``` 在上面的示例中,`#pragma pack(push, 1)`指令将当前的对齐方式推入一个栈中,并将对齐方式设置为1字节对齐。然后定义了一个包含不同类型成员的结构体。最后,使用`#pragma pack(pop)`指令将对齐方式恢复为默认值。 请注意,修改结构体的字节对齐方式可能会导致内存浪费或者访问错误,因此在修改字节对齐方式时要特别小心。建议仅在必要时进行修改,并确保了解目标平台的字节对齐要求。 希望这能回答你的问题!如果还有疑问,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值