码迷,mamicode.com
首页 > 其他好文 > 详细

【信息表示】地址对齐

时间:2015-04-09 21:53:52      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:

   本节研究地址对齐的相关问题;


地址对齐

说明几点:

(1)地址对齐可以简化处理器和存储器系统之间的硬件设计;如果可以保证所有的int类型地址对齐成4的倍数,就可以使用一个存储器操作读或写值,相反如果一个int型的变量存放在奇地址上,那么要进行两次存储器读后进行拼凑成int型变量才可以;

(2)在GCC中,2字节数据类型(如short)地址对齐必须是2的倍数,因此地址最低位必须是0,而较大的数据类型(如int、int*、float、包括long long、double、long double)的地址对齐必须是4的倍数,因此地址最低两位必须是00;注意Mircosoft对齐更严格,任何K字节的基本对象的地址必须是K的倍数,也就是说long long、double这样的地址必须是8的倍数;

(3)long double(实际上为10个字节),在GCC和windows都中分配12个字节,都进行4字节地址对齐;

(4)在#pragma pack (n)中,n为1,2,4,8这样的2的次方;在缺省情况下,编译器按照数据类型的自身边界进行对齐,如short的对齐边界为2字节;但是在指定了#pragma pack (n)后,对于所有比n大的数据类型边界都均按照n来对齐;

(5)在__attribute__((aligned(n))中,n为1,2,4,8这样的2的次方;它表示在一个结构体(联合体)在分配空间时的地址对齐方式,最后的地址一定是按照n字节对齐的;


实验验证

(注:本文的编译器为GCC)

#pragma pack示例

代码片段如下:

struct P1
{
  float a;
  char b;
  int c;
  char d;
};

#pragma pack (1)
struct P2
{
  float a;
  char b;
  int c;
  char d;
};
#pragma pack ()

#pragma pack (2)
struct P3
{
  float a;
  char b;
  int c;
  char d;
};
#pragma pack ()

#pragma pack (4)
struct P4
{
  float a;
  char b;
  int c;
  char d;
};
#pragma pack ()

#pragma pack (8)
struct P5
{
  float a;
  char b;
  int c;
  char d;
};
#pragma pack ()

int main(void)
{
  printf("P1, size %d\n", sizeof(P1));
  printf("P2, size %d\n", sizeof(P2));
  printf("P3, size %d\n", sizeof(P3));
  printf("P4, size %d\n", sizeof(P4));
  printf("P5, size %d\n", sizeof(P5));
 
  printf("P1, address------\n"); 
  P1 p1;
  printf("%p\n", &p1);
  printf("a: %p\n", &p1.a);
  printf("b: %p\n", &p1.b);
  printf("c: %p\n", &p1.c);
  printf("d: %p\n\n", &p1.d);
  
  printf("P2, address------\n"); 
  P2 p2;
  printf("%p\n", &p2);
  printf("a: %p\n", &p2.a);
  printf("b: %p\n", &p2.b);
  printf("c: %p\n", &p2.c);
  printf("d: %p\n\n", &p2.d);
  
  printf("P3, address------\n"); 
  P3 p3;
  printf("%p\n", &p3);
  printf("a: %p\n", &p3.a);
  printf("b: %p\n", &p3.b);
  printf("c: %p\n", &p3.c);
  printf("d: %p\n\n", &p3.d);
  
  printf("P4, address------\n"); 
  P4 p4;
  printf("%p\n", &p4);
  printf("a: %p\n", &p4.a);
  printf("b: %p\n", &p4.b);
  printf("c: %p\n", &p4.c);
  printf("d: %p\n\n", &p4.d);
  
  printf("P5, address------\n"); 
  P5 p5;
  printf("%p\n", &p5);
  printf("a: %p\n", &p5.a);
  printf("b: %p\n", &p5.b);
  printf("c: %p\n", &p5.c);
  printf("d: %p\n\n", &p5.d);
}

输出如下:

P1, size 16
P2, size 10
P3, size 12
P4, size 16
P5, size 16
P1, address------
0xbfacc840
a: 0xbfacc840
b: 0xbfacc844
c: 0xbfacc848
d: 0xbfacc84c

P2, address------
0xbfacc836
a: 0xbfacc836
b: 0xbfacc83a
c: 0xbfacc83b
d: 0xbfacc83f

P3, address------
0xbfacc82a
a: 0xbfacc82a
b: 0xbfacc82e
c: 0xbfacc830
d: 0xbfacc834

P4, address------
0xbfacc818
a: 0xbfacc818
b: 0xbfacc81c
c: 0xbfacc820
d: 0xbfacc824

P5, address------
0xbfacc808
a: 0xbfacc808
b: 0xbfacc80c
c: 0xbfacc810
d: 0xbfacc814
说明几点:

(1)P1和P4是同样的地址对齐,都是4地址对齐;而对于P2各数据类型只进行1地址对齐,因此大小就是所有数据类型的大小;对于P3由于#pragma pack (2),因此所有的数据类型对齐边界都不会超过2,因此像int,float这样的数据类型的对齐边界也是2;

(2)对于P4和P5来说,由于数据类型中任何一个数据类型的对齐边界最大为4,而#pragma pack (4或8)的指定并不会影响这些数据类型的对齐边界;


上述各个结构体的示意图如下:

技术分享



__attribute__((aligned(n)))示例

代码片段如下

struct P1
{
  float a;
  char b;
  int c;
  char d;
}__attribute__((aligned(4)));

#pragma pack (1)
struct P2
{
  float a;
  char b;
  int c;
  char d;
}__attribute__((aligned(4)));
#pragma pack ()

#pragma pack (2)
struct P3
{
  float a;
  char b;
  int c;
  char d;
}__attribute__((aligned(4)));
#pragma pack ()

int main(void)
{
  printf("P1, size %d\n", sizeof(P1));
  printf("P2, size %d\n", sizeof(P2));
  printf("P3, size %d\n", sizeof(P3));

  printf("P1, address------\n"); 
  P1 p1;
  printf("%p\n", &p1);
  printf("a: %p\n", &p1.a);
  printf("b: %p\n", &p1.b);
  printf("c: %p\n", &p1.c);
  printf("d: %p\n\n", &p1.d);
  
  printf("P2, address------\n"); 
  P2 p2;
  printf("%p\n", &p2);
  printf("a: %p\n", &p2.a);
  printf("b: %p\n", &p2.b);
  printf("c: %p\n", &p2.c);
  printf("d: %p\n\n", &p2.d);
  
  printf("P3, address------\n"); 
  P3 p3;
  printf("%p\n", &p3);
  printf("a: %p\n", &p3.a);
  printf("b: %p\n", &p3.b);
  printf("c: %p\n", &p3.c);
  printf("d: %p\n\n", &p3.d);
}

输出如下:

P1, size 16
P2, size 12
P3, size 12
P1, address------
0xbf98d9e0
a: 0xbf98d9e0
b: 0xbf98d9e4
c: 0xbf98d9e8
d: 0xbf98d9ec

P2, address------
0xbf98d9d4
a: 0xbf98d9d4
b: 0xbf98d9d8
c: 0xbf98d9d9
d: 0xbf98d9dd

P3, address------
0xbf98d9c8
a: 0xbf98d9c8
b: 0xbf98d9cc
c: 0xbf98d9ce
d: 0xbf98d9d2
说明几点:

(1)__attribute__((aligned(4)))仅仅是将结构体本身对齐,对结构体的内部数据的对齐方式是没有影响的;


结构体示意图如下:

技术分享




long long和double示例

代码片段如下

struct P1
{
  char a;
  double b;
  char c;
  long long d;
};

int main(void)
{
  printf("P1, size %d\n", sizeof(P1));

  printf("P1, address------\n"); 
  P1 p1;
  printf("%p\n", &p1);
  printf("a: %p\n", &p1.a);
  printf("b: %p\n", &p1.b);
  printf("c: %p\n", &p1.c);
  printf("d: %p\n\n", &p1.d);
}

输出如下:

P1, size 24
P1, address------
0xbfbe4348
a: 0xbfbe4348
b: 0xbfbe434c
c: 0xbfbe4354
d: 0xbfbe4358

说明几点:

(1)double和long long在GCC中并不是按照8个字节对齐的,而是按照4字节对齐的;和windows中不一样;


结构体示意图如下:

技术分享

【信息表示】地址对齐

标签:

原文地址:http://blog.csdn.net/skyuppour/article/details/44964265

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!