struct 成员的对齐方式

//用一个宏定义FIND求结构体struct s中某个成员变量member相对struct s的偏移量.
//思考:若struct s的地址为0,则其成员member的地址就是其相对于s的偏移量
//扩展: <1>sizeof(struct s) 不一定等于 sizeof(struct s中的每一个成员)的和
//      <2>结构体大小不仅由成员的大小决定(sizeof(member)),而且还要考虑编译器用来优化的对齐。
// 编译器的优化对齐(alignment), 是为了减少访问总线的次数。
//由于数据总线的位数(由机器字长决定),为了减少数据访问的次数。
//这样可以保证机器字长整数倍的基本类型(而非自定义类型)
//能够通过 sizeof(基本类型)/sizeof(size_t)次总线访问完成;
//通过实验, 我得出的对齐规则是:
// char  偏移地址二进制的最后一位:0/1;即1的倍数的地址对齐性;即任意对齐性;
// short 偏移地址二进制的最后一位:0;  即2的倍数地址的对齐性;即偶数地址对齐性;
// int     偏移地址二进制的最后两位:00; 即4的倍数的地址对齐性;

// float  偏移地址二进制的最后两位:00; 即4的倍数的地址对齐性;

// long  偏移地址二进制的最后两位:00; 即4的倍数的地址对齐性;

// long long   偏移地址二进制的最后三位:000;即8的倍数的地址对齐性;
// double偏移地址二进制的最后三位:000;即8的倍数的地址对齐性;
//总之,struct中基本类型成员的偏移地址时一定是sizeof(基本类型)的整数倍,
//自定义类型偏移地址的对齐性是任意的.
//推过这种方式,就能解释sizeof(struct s)不等于所有成员的sizeof的和。
// sizeof(struct s) 除了满足以上偏移地址对齐外,
// 是其大小为其基本类型成员的sizeof值最大的成员的sizeof值的整数倍

// 也就是说为最大的基本类型的sizeof值得整数倍。

程序举例:

[cpp]  view plain  copy
  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4.   
  5.   
  6. struct cc {  
  7.     char a;  
  8.     char c[6];  
  9.     char b;  
  10. };  
  11. struct student {  
  12.     int a;  
  13.     char b[20];  
  14.     char c;  
  15.     struct cc cc;  
  16.     double d;  
  17. };  
  18.   
  19.   
  20.   
  21.   
  22.   
  23. //用一个宏定义FIND求结构体struct s中某个成员变量member相对struct s的偏移量.  
  24. //思考:若struct s的地址为0,则其成员member的地址就是其相对于s的偏移量  
  25. //扩展: <1>sizeof(struct s) 不一定等于 sizeof(struct s中的每一个成员)的和  
  26. //      <2>结构体大小不仅由成员的大小决定(sizeof(member)),而且还要考虑编译器用来优化的对齐。  
  27. // 编译器的优化对齐(alignment), 是为了减少访问总线的次数。  
  28. //由于数据总线的位数(由机器字长决定),为了减少数据访问的次数。  
  29. //这样可以保证机器字长整数倍的基本类型(而非自定义类型)  
  30. //能够通过 sizeof(基本类型)/sizeof(size_t)此总线访问完成;  
  31. //通过实验, 我得出的对齐规则是:  
  32. // char  偏移地址二进制的最后一位:0/1;即1的倍数的地址对齐性;即任意对齐性;  
  33. // short 偏移地址二进制的最后一位:0;  即2的倍数地址的对齐性;即偶数地址对齐性;  
  34. // int   偏移地址二进制的最后两位:00; 即4的倍数的地址对齐性;  
  35. // float 偏移地址二进制的最后两位:00; 即4的倍数的地址对齐性;  
  36. // long  偏移地址二进制的最后三位:000;即8的倍数的地址对齐性;  
  37. // double偏移地址二进制的最后三位:000;即8的倍数的地址对齐性;  
  38. //总之,struct中基本类型成员的偏移地址时一定是sizeof(基本类型)的整数倍,  
  39. //自定义类型偏移地址的对齐性是任意的.  
  40. //推过这种方式,就能解释sizeof(struct s)不等于所有成员的sizeof的和。  
  41. // sizeof(struct s) 除了满足以上偏移地址对齐外,  
  42. // 是其大小为其基本类型成员的sizeof值最大的成员的sizeof值的整数倍  
  43. // 也就是说为最大的基本类型的sizeof值得整数倍。  
  44.   
  45. #define FIND(s, member)  (size_t)(&((*((s *)((void *)0))).member))  
  46. #define FIND1(s, member) (size_t)(&(*((s *)0)).member)  
  47. #define FIND2(s, member) (size_t)(&(((s *)0)->member))  
  48.   
  49. #define DISPLACEMENT1(structure, member) (size_t) &((*((structure *)0)).member)  
  50. #define DISPLACEMENT2(structure, member) (size_t) &(((structure *)0)->member)  
  51.   
  52. struct c {  
  53.     char a;     //1字节 [0, 0]  
  54.     char c[5];  //5字节 [1, 5]  
  55.  //char cc[2];  //填充2字节 [6, 7]  
  56.                 //8字节  
  57.   
  58.     int  b;    //12字节 [8, 11]  
  59.   
  60.     char d;    //14字节 [12, 13] //填充一字节  
  61.     short e;   //16字节 [14, 15]  
  62.   
  63.     char f;    //17字节 [16, 16]  
  64.     char g;    //18字节 [17, 17]  
  65.     char h;    //19字节 [18, 18]  
  66.     //char i;  //20字节  [19, 19]  
  67.     short s;   //24字节 [20, 23]  
  68. };  
  69.   
  70. struct ccc {  
  71.     char a;     // 0  
  72.     int  b;     // 4  
  73.     char c[5];  // 8  
  74.     char d;     // 13  
  75.     double e;   // 16  
  76.     char f;     // 24  
  77.     char g;     // 25  
  78.     //int h;     // 28  
  79. };  
  80.   
  81.   
  82. struct d {  
  83.     char a;  //0  
  84.     short b; //2  
  85.     int c;   //4  
  86.     char d;  //8  
  87.     double f;//16  
  88. };  
  89.   
  90. struct e {  
  91.     char a;   //0  
  92.     double b; //8  
  93.     char c;   //16  
  94. };           //24  
  95.   
  96. struct f {  
  97.     char a;   // 0  
  98.     float b;  // 4  
  99.     char c;   // 8  
  100. };  
  101.   
  102. struct g {  
  103.     char a;  
  104.     short b;  
  105.     char c;  
  106. };  
  107.          // 12  
  108. int main()  
  109. {  
  110.     cout << FIND(student, a) << endl;  
  111.     cout << FIND(student, b) << endl;  
  112.     cout << FIND(student, c) << endl;  
  113.     cout << FIND(student, d) << endl;  
  114.     cout << endl;  
  115.   
  116.     cout << FIND1(student, a) << endl;  
  117.     cout << FIND1(student, b) << endl;  
  118.     cout << FIND1(student, c) << endl;  
  119.     cout << FIND1(student, d) << endl;  
  120.     cout << endl;  
  121.   
  122.   
  123.     cout << FIND2(student, a) << endl;  
  124.     cout << FIND2(student, b) << endl;  
  125.     cout << FIND2(student, c) << endl;  
  126.     cout << FIND2(student, d) << endl;  
  127.     cout << endl;  
  128.   
  129.   
  130.   
  131.   
  132.   
  133.     cout << DISPLACEMENT1(student, a) << endl;  
  134.     cout << DISPLACEMENT1(student, b) << endl;  
  135.     cout << DISPLACEMENT1(student, c) << endl;  
  136.     cout << DISPLACEMENT1(student, d) << endl;  
  137.     cout << endl;  
  138.   
  139.   
  140.     cout << DISPLACEMENT2(student, a) << endl;  
  141.     cout << DISPLACEMENT2(student, b) << endl;  
  142.     cout << DISPLACEMENT2(student, c) << endl;  
  143.     cout << DISPLACEMENT2(student, cc) << endl;  
  144.     cout << DISPLACEMENT2(student, d) << endl;  
  145.     cout << "sizeof(student) = " << sizeof(student) << endl;  
  146.     cout << endl;  
  147.   
  148.     cout << DISPLACEMENT2(c, a) << endl;  
  149.     cout << DISPLACEMENT2(c, b) << endl;  
  150.     cout << DISPLACEMENT2(c, c) << endl;  
  151.     cout << DISPLACEMENT2(c, d) << endl;  
  152.     cout << DISPLACEMENT2(c, e) << endl;  
  153.     cout << DISPLACEMENT2(c, f) << endl;  
  154.     cout << DISPLACEMENT2(c, g) << endl;  
  155.     cout << DISPLACEMENT2(c, h) << endl;  
  156.    // cout << DISPLACEMENT2(c, i) << endl;  
  157.     cout << DISPLACEMENT2(c, s) << endl;  
  158.     cout << "sizeof(c) = " << sizeof(c) << endl;  
  159.     cout << "sizeof(c.c) = " << sizeof(((c*) 0)->c) << endl;  
  160.     cout << endl;  
  161.   
  162.     cout << DISPLACEMENT2(ccc, a) << endl;  
  163.     cout << DISPLACEMENT2(ccc, b) << endl;  
  164.     cout << DISPLACEMENT2(ccc, c) << endl;  
  165.     cout << DISPLACEMENT2(ccc, d) << endl;  
  166.     cout << DISPLACEMENT2(ccc, e) << endl;  
  167.     cout << DISPLACEMENT2(ccc, f) << endl;  
  168.     cout << DISPLACEMENT2(ccc, g) << endl;  
  169.     //cout << DISPLACEMENT2(ccc, h) << endl;  
  170.     cout << "sizeof(ccc) = " << sizeof(ccc) << endl;  
  171.     cout << endl;  
  172.   
  173.     student s;  
  174.     cout << sizeof(s.cc) << endl; //you  
  175.     cout << sizeof(c) << endl;  
  176.     cout << sizeof(ccc) << endl;  
  177.   
  178.   
  179.     cout << "sizeof(d) = "  << sizeof(d) << endl;  
  180.     cout << DISPLACEMENT2(d, a) << endl;  
  181.     cout << DISPLACEMENT2(d, b) << endl;  
  182.     cout << DISPLACEMENT2(d, c) << endl;  
  183.     cout << DISPLACEMENT2(d, d) << endl;  
  184.     cout << DISPLACEMENT2(d, f) << endl;  
  185.     cout << endl;  
  186.   
  187.     cout << endl;  
  188.     cout << "sizeof(cc) = " << sizeof(cc) << endl;  
  189.     cout << "sizeof(student) = " << sizeof(student) << endl;  
  190.     cout << "sizeof(ccc) = " << sizeof(ccc)  << endl;  
  191.     cout << "sizeof(c) = " << sizeof(c) << endl;  
  192.     cout << "sizeof(d) = " << sizeof(d) << endl;  
  193.     cout << "sizeof(e) = " << sizeof(e) << endl;  
  194.     cout << "sizeof(f) = " << sizeof(f) << endl;  
  195.     cout << "sizeof(g) = " << sizeof(g) << endl;  
  196.   
  197.     cout << "Hello world!" << endl;  
  198.     return 0;  
  199. }  

补充:

首先要明确sizeof不是函数,也不是一元运算符,//这个有待商榷,因为运算符优先级里有它。
他是个类似宏定义的特殊关键字,sizeof();
括号内在编译过程中是不被编译的,而是被替代类型,
如 int a=8;sizeof(a);
在编译过程中,它不管a的值是什么,只是被替换成类型 sizeof(int); 结果为4.
如果sizeof(a=6);呢,也是一样的转换成a的类型,但是要注意 因为a=6是不被编译的,所以执行完sizeof(a=6);a的值还是8,是不变的!


记住以下几个结论:
1.unsigned影响的只是最高位bit的意义(正负),数据长度不会被改变的。所以sizeof(unsigned int) == sizeof(int);
2.自定义类型的sizeof取值等同于它的类型原形。如typedef short WORD;sizeof(short) == sizeof(WORD)。
3.对函数使用sizeof,在编译阶段会被函数返回值的类型取代。如:int f1(){return 0;};
cout < <sizeof(f1()) < <endl; // f1()返回值为int,因此被认为是int
4.只要是指针,大小就是4。如:cout < <sizeof(string*) < <endl; // 4
5.数组的大小是各维数的乘积*数组元素的大小。如:

char a[] = “abcdef “;
int b[20] = {3, 4};
char c[2][3] = { 'a', 'b'};
cout << sizeof(a) << endl; // 7
cout << sizeof(b) << endl; // 20*4
cout << sizeof(c) << endl; // 6
数组a的大小在定义时未指定,编译时给它分配的空间是按照初始化的值确定的,也就是7,包括‘\0’的。


6.字符串的sizeof和strlen,用例子说明:
char a[] = “abcdef “;
char b[20] = “abcdef “;
string s = “abcdef “;
cout << strlen(a) << endl; // 6,字符串长度
cout << sizeof(a) << endl; // 7,字符串容量
cout << strlen(b) << endl; // 6,字符串长度
cout << sizeof(b) << endl; // 20,字符串容量
cout << sizeof(s) << endl; //4, 这里不代表字符串的长度,而是string类的大小
cout << strlen(s) << endl; // 错误!s不是一个字符指针。

cout << strlen(s.c_str()) << endl;

a[1] = '\0';
cout < <strlen(a) < <endl; // 1
cout < <sizeof(a) < <endl; // 7,sizeof是恒定的


参考 :http://en.wikipedia.org/wiki/Data_structure_alignment

http://www.ibm.com/developerworks/library/pa-dalign/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值