结构体的对齐有自然对齐和强制类型对齐,可以从三方面来考虑:内存大小、访问效率和跨平台移植。
在默认情况下,编译器对结构中的对齐方式为自然对齐的。但不同平台的自然对齐方式可能会不一样。 而自然对齐的意思是:
对齐跟数据在内存中的位置有关,如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐。
1.访问效率:
需要字节对齐的原因之一在于CPU访问数据的效率问题。假设整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次内存,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。而如果变量在自然对齐位置上,则只要一次就可以取出数据。
2.占用内存大小
对于标准数据类型,只要它的长度的整数倍就行了,非标准数据类型按下面原则对齐:
struct test{ char c; short s; char c2; int i; }; | struct test1{ char c; char c2; short s; int i;}; | 数组 :按照基本数据类型对齐,第一个对齐了后面的自然也就对齐了。 联合 :按其包含的长度最大的数据类型对齐。 结构体: 结构体中每个数据类型都要对齐。 第一个结构为12 第二个为8 |
struct T
{
char ch;
double d ;
};
在VC下,按8字节对齐是16字节,而在GCC下是12字节。
若采用默认的自然对齐方式,一方面在结构设计时要合理安排各变量的存放顺序。另一方面若要占用小的空间则可以以牺牲效率为代价。如typedef unsigned char uc;
typedef unsigned short us;
struct str1{
uc a[3];
us b;
};
struct str2{
uc a[3];
uc b[2];
};
第一个结构为6,第二个结构大小为5.
对于整个结构体来说,它的默认对齐方式就是它的所有成员使用的对齐参数中最大的一个,
#pragma pack(8)
struct s1{ short a; long b; };
struct s2{ char c;//4,以1对齐 _ _ _1
s1 d;//8以4对齐 1 1 1 1/ 1 1 1 1 long long e;//12,以8对齐 _ _ _ _ 1 1 1 1/ 1 1 1 1 };
#pragma pack()
.sizeof(s2) = 243.跨平台移植
在设计不同CPU下的通信协议时,或者编写硬件驱动程序时寄存器的结构这两个地方都需要按一字节对齐。即使看起来本来就自然对齐的也要使其对齐,以免不同的编译器生成的代码不一样.
如网络编程若数据包的大小在不同平台下不一样,则会混乱。
4。强制对齐
4.1 windows中<span style="font-family:SimSun;">#pragma pack(n)则强制为n字节对齐,个人理解它的意思是,若原类型变量的大小(sizeof(type))小于等于n,则存放该类型变量的起始地址必须是该类型大小的整数倍,而不一定是要n的整数倍。如short 类型变量ss大小为2字节,若#pragma pack(n)中的n为2,则ss的地址则一定是2的整数倍。若n=4,则ss的地址则一定是2的整数倍,但不一定为4的整数倍。若n=1,则它的地址为1的整数倍速。</span>
<span style="font-family:SimSun;">若原类型变量的大小(sizeof(type))大于n,则它的地始地址一定是n的整数倍。</span>
<span style="font-family:SimSun;">如n=4,则double大小为8,但它的地址一定是4的整数倍。</span>
<span style="font-family:SimSun;">使用伪指令#pragma pack (),取消自定义字节对齐方式,如</span>
<span style="font-family:SimSun;">在一个结构中,结构体的大小一定是该结构最终采用对齐方式大小的整数倍。如struct str1,不管#pragma pack(n)中的n为多少(1除外),它的最终对齐只要是2的整数倍,从而它的大小为6.即使n=8,它的大小还是6.而</span>
<span style="font-family:SimSun;">struct str3若n=2,则结构大小为10,</span>
若n=4,则最终的对齐是以4对齐的,所以结构大小也一定为4的倍数,12.
struct str1{
uc a[3];
us b;
};
struct str2{
uc a[3];
uc b[2];
};
struct str3{
char c;
double d;
};
若前面加了
#pragma pack(4)
struct str4{
uc a[3];
};
则sizeof(struct str4)=3,对齐只对大于n中的有效。
—————————————————————————————
#pragma pack(4)
struct str1{
uc a[3];
us b;
};
struct str2{
uc a[3];
uc b[2];
};
struct str3{
char c;
double d;
};//VC不支持__attribute__((packed));
struct str4{
uc a[3];
};
printf("%d\n",sizeof(struct str1));//6
printf("%d\n",sizeof(struct str2));//5
printf("%d\n",sizeof(struct str3));//12
printf("%d\n",sizeof(struct str4));//3<span style="white-space:pre">
只有16变成了12;
若改为#pragma pack(8),则为6,5,16,3<
————————————————————————
__attribute__语法格式为:
__attribute__ ((attribute-list))
GNU CC需要使用 –Wall编译器来击活该功能,这是控制警告信息的一个很好的方式。
它可以改变函数、变量、和类型的部分属性。具体可以看上面中的链接。
4.1.1 用于限定变量的属性
You may also specify attributes with `__' preceding and following each keyword. This allows you to use them in header files without being concerned about a possible macro of the same name. For example, you may use __aligned__ instead of aligned .大概意思是:在属性列表中,可以在属性的前后可双下横线,这与没加的效果一样,且可以防止重命名。 __attribute__ ((packed)) 与__attribute__((__packed__))的效果是一样的。 |
aligned (
alignment) 规定结构或变量的地址为alignment的整数倍。
This attribute specifies a minimum alignment for the variable or structure field, measured in bytes. For example, the declaration: int x __attribute__ ((aligned (16))) = 0; 变量或结构的边界最小对齐方式。如 某个变量的存储地址必须是alignment的整数倍。 上面的x的地址一定是16的整数倍,与wind中的不同,但它的大小 还是4; causes the compiler to allocate the global variable this could be used in conjunction with an 16-byte aligned operands. You can also specify the alignment of structure fields. For example, to create a double-word aligned struct foo { int x[2] __attribute__ ((aligned (8))); };
|
linux中的某个结构。
struct cpuinfo_alpha {
unsigned long loops_per_jiffy;
unsigned long last_asn;
int need_new_asn;
int asn_lock;
unsigned long ipi_count;
unsigned long prof_multiplier;
unsigned long prof_counter;
unsigned char mcheck_expected;
unsigned char mcheck_taken;
unsigned char mcheck_extra;
} __attribute__((aligned(64)));
(2)
packed 一字节或一位对齐
The packed
attribute specifies that a variable or structure field
should have the smallest possible alignment—one byte for a variable, and one bit for a field, unless you specify a larger value with thealigned
attribute. Here is a structure in which the fieldx
is packed, so that it immediately followsa
:
大小为9,struct foo{ char a; int x[2] __attribute__ ((packed)); };