结构体的对齐方式

	结构体的对齐有自然对齐和强制类型对齐,可以从三方面来考虑:内存大小、访问效率和跨平台移植。
	在默认情况下,编译器对结构中的对齐方式为自然对齐的。但不同平台的自然对齐方式可能会不一样。	而自然对齐的意思是:

对齐跟数据在内存中的位置有关,如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐

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

结构中按结构中最大长度的类型进行对齐,但不会超过最大的对齐类型。如VC下最大的对齐为8字节,而linux中的gcc编译器最大为4字节对齐。如

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) = 24

3.跨平台移植

 在设计不同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(1)
则str1=str2=5;str3=9.
若为
#pragma pack(2)
则str1=6、str2=5;str3=10.
若在struct str3之前加了:pragma pack (),则它的结构大小写为16.

#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<
————————————————————————
4.1 gcc中
在linux环境下,也支持上面的#pragma pack(n)方式。这与win中一样。
但中给出了GNU编译器的另一种方式。
__attribute__机制使得GNU编译器能够进行一些错误检查,它的目的之一就是为了与非GNU编译器兼容
注意:__attribute__前后都有两个下划线,并且后面会紧跟两对括弧(若只一对,则编译不过),括弧里面是相应的__attribute__参数。
	__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__))的效果是一样的。
(1)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 x on a 16-byte boundary. On a 68040, 

this could be used in conjunction with an asm expression to access themove16 instruction which requires 

16-byte aligned operands.

You can also specify the alignment of structure fields. 

For example, to create a double-word aligned int pair, you could write:

          struct foo { int x[2] __attribute__ ((aligned (8))); };

The aligned attribute can only increase the alignment; 

but you can decrease it by specifying packed as well. See below.

Note that the effectiveness of aligned attributes may be 

limited by inherent limitations in your linker.

On many systems, the linker is only able to arrange for variables

to be aligned up to a certain maximum alignment. 

(For some linkers, the maximum supported alignment may be very very small.)

If your linker is only able to align variables up to a maximum of 8 byte alignment, 

then specifying aligned(16) in an __attribute__ will still only provide you with 8 byte alignment.

See your linker documentation for further information. 

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 the aligned attribute.
Here is a structure in which the field x is packed, so that it immediately follows a:
struct foo{
            char a;
            int x[2] __attribute__ ((packed));
          };
大小为9,


                
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值