结构体存储方式之强制对齐
(2016-05-08 14:21:01)
标签:
it |
分类: JAVA/C#/Cpp/C语言/Python |
参考:C语言结构体对齐
参考:结构体大小size的计算
参考:C语言字节对齐
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
{
}data;
此时,sizeof(data)为8,编译器进行了优化对齐,而
typedef struct DATA
{
}__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) :
比如:__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.编译器自动分配出来结构体的内存(比如定义为全局变量或局部变量)肯定是对齐的。