加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

结构体存储方式之强制对齐

(2016-05-08 14:21:01)
标签:

it

分类: JAVA/C#/Cpp/C语言/Python

1、#pragma pack(n)对齐方式:
· 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
· 使用伪指令#pragma pack (),取消自定义字节对齐方式。

//#pragma pack(push, DD, 1)  // 将当前pack设置压栈保存 
//#pragma pack(1)                   // 必须在结构体定义之前使用,这是为了让结构体中各成员按1字节对齐 

typedef struct tagBITMAPFILEHEADER {     // bmfh 
unsigned short bfType; 
unsigned long  bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long  bfOffBits;
}  __attribute__ ((packed)) BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER {    // bmih 
unsigned long  biSize;
unsigned long  biWidth;
unsigned long  biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long  biCompression;
unsigned long  biSizeImage;
unsigned long  biXPelsPerMeter;
unsigned long  biYPelsPerMeter;
unsigned long  biClrUsed;
unsigned long  biClrImportant;
}  __attribute__ ((packed)) BITMAPINFOHEADER;

//#pragma pack(pop)                               // 恢复先前的pack设置 


2、__attribute__((packed))对齐方式:
默认情况下,gcc编译器会将数据进行优化对齐,以提高存取数据的效率。而attribute__ ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有的语法。举个例子分析一下:
定义如下结构体,
typedef struct DATA
{
   uint8_t  a;
   int      n;
}data;
此时,sizeof(data)为8,编译器进行了优化对齐,而
typedef struct DATA
{
   uint8_t  a;
   int      n;
}__attribute__((packed))data;
此时,sizeof(data)为5,数据按实际占用字节数进行对齐。
注意:attribute前后各有两个下划线。

3、__attribute((aligned (n)))对齐方式:
我们可以按照自己设定的对齐大小来编译程序,GNU使用__attribute__选项来设置,比如我们想让刚才的结构按一字节对齐,我们可以这样定义结构体
  
  struct stu{
   char sex;
   int length;
   char name[10];
  }__attribute__ ((aligned (1))); 
  
  struct stu my_stu;

  则sizeof(my_stu)可以得到大小为15。
  
  上面的定义等同于
  struct stu{
   char sex;
   int length;
   char name[10];
  }__attribute__ ((packed)); 
  struct stu my_stu;
   
  __attribute__((packed))得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐.

总结:
· __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。
· __attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

4、__align(num) 对齐方式:
__align(num)  :
   这个用于修改最高级别对象的字节边界。在汇编中使用LDRD或者STRD时  
   就要用到此命令__align(8)进行修饰限制,来保证数据对象是相应对齐。  
   这个修饰对象的命令最大是8个字节限制,可以让2字节的对象进行4字节  
   对齐,但是不能让4字节的对象2字节对齐。  
   __align是存储类修改,他只修饰最高级类型对象,不能用于结构或者函数对象。 
比如:__align(4) u8 mem1base[MEM1_MAX_SIZE];//保证分配的数组空间4字节对齐,同时保证数组首地址可被4整除

5、__packed对齐方式:
__packed是进行一字节对齐  
  1.不能对packed的对象进行对齐  
  2.所有对象的读写访问都进行非对齐访问  
  3.float及包含float的结构联合及未用__packed的对象将不能字节对齐  
  4.__packed对局部整形变量无影响  
  5.强制由unpacked对象向packed对象转化是未定义,整形指针可以合法定  
  义为packed。  
     __packed int* p;  //__packed int 则没有意义  
  6.对齐或非对齐读写访问带来问题  
  __packed struct STRUCT_TEST  
 
  char a;  
  int b;  
  char c;  
    //定义如下结构此时b的起始地址一定是不对齐的  
         //在栈中访问b可能有问题,因为栈上数据肯定是对齐访问[from CL]  

__packed typedef union
{
float   Cal_F[CALIB_VOLT_DATANUM];
uint8_t data[CALIB_VOLT_DATANUM * 4];
} CAL_VOLT;


在 Cotex-M3 programming manual 中有提到对齐问题
  1.通常编译器在生成代码的时候都会进行结构体填充,保证(结构体内部成员)最高性能的对齐方式。
  2.编译器自动分配出来结构体的内存(比如定义为全局变量或局部变量)肯定是对齐的。
  3.查阅帮助文档的malloc部分,mdk的标准malloc申请的内存区时8字节对齐的。
  4.若自定义的malloc函数本身没有对分配的内存实现4字节或以上的对齐操作,分配出来的不对齐的内存,编译器是不知道的,所以很可能会产生问题。
     此时最好的解决方式在内存池数组前添加__align(4)关键字,只需保证自定义malloc分配出来的首地址是4字节对齐。
     比如:__align(4) u8 mem1base[MEM1_MAX_SIZE];

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有