struct 成员的对齐方式
2016-12-11 21:42
281 查看
//用一个宏定义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
#include <iostream>
using namespace std;
struct cc {
char a;
char c[6];
char b;
};
struct student {
int a;
char b[20];
char c;
struct cc cc;
double d;
};
//用一个宏定义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 偏移地址二进制的最后三位:000;即8的倍数的地址对齐性;
// double偏移地址二进制的最后三位:000;即8的倍数的地址对齐性;
//总之,struct中基本类型成员的偏移地址时一定是sizeof(基本类型)的整数倍,
//自定义类型偏移地址的对齐性是任意的.
//推过这种方式,就能解释sizeof(struct s)不等于所有成员的sizeof的和。
// sizeof(struct s) 除了满足以上偏移地址对齐外,
// 是其大小为其基本类型成员的sizeof值最大的成员的sizeof值的整数倍
// 也就是说为最大的基本类型的sizeof值得整数倍。
#define FIND(s, member) (size_t)(&((*((s *)((void *)0))).member))
#define FIND1(s, member) (size_t)(&(*((s *)0)).member)
#define FIND2(s, member) (size_t)(&(((s *)0)->member))
#define DISPLACEMENT1(structure, member) (size_t) &((*((structure *)0)).member)
#define DISPLACEMENT2(structure, member) (size_t) &(((structure *)0)->member)
struct c {
char a; //1字节 [0, 0]
char c[5]; //5字节 [1, 5]
//char cc[2]; //填充2字节 [6, 7]
//8字节
int b; //12字节 [8, 11]
char d; //14字节 [12, 13] //填充一字节
short e; //16字节 [14, 15]
char f; //17字节 [16, 16]
char g; //18字节 [17, 17]
char h; //19字节 [18, 18]
//char i; //20字节 [19, 19]
short s; //24字节 [20, 23]
};
struct ccc {
char a; // 0
int b; // 4
char c[5]; // 8
char d; // 13
double e; // 16
char f; // 24
char g; // 25
//int h; // 28
};
struct d {
char a; //0
short b; //2
int c; //4
char d; //8
double f;//16
};
struct e {
char a; //0
double b; //8
char c; //16
}; //24
struct f {
char a; // 0
float b; // 4
char c; // 8
};
struct g {
char a;
short b;
char c;
};
// 12
int main()
{
cout << FIND(student, a) << endl;
cout << FIND(student, b) << endl;
cout << FIND(student, c) << endl;
cout << FIND(student, d) << endl;
cout << endl;
cout << FIND1(student, a) << endl;
cout << FIND1(student, b) << endl;
cout << FIND1(student, c) << endl;
cout << FIND1(student, d) << endl;
cout << endl;
cout << FIND2(student, a) << endl;
cout << FIND2(student, b) << endl;
cout << FIND2(student, c) << endl;
cout << FIND2(student, d) << endl;
cout << endl;
cout << DISPLACEMENT1(student, a) << endl;
cout << DISPLACEMENT1(student, b) << endl;
cout << DISPLACEMENT1(student, c) << endl;
cout << DISPLACEMENT1(student, d) << endl;
cout << endl;
cout << DISPLACEMENT2(student, a) << endl;
cout << DISPLACEMENT2(student, b) << endl;
cout << DISPLACEMENT2(student, c) << endl;
cout << DISPLACEMENT2(student, cc) << endl;
cout << DISPLACEMENT2(student, d) << endl;
cout << "sizeof(student) = " << sizeof(student) << endl;
cout << endl;
cout << DISPLACEMENT2(c, a) << endl;
cout << DISPLACEMENT2(c, b) << endl;
cout << DISPLACEMENT2(c, c) << endl;
cout << DISPLACEMENT2(c, d) << endl;
cout << DISPLACEMENT2(c, e) << endl;
cout << DISPLACEMENT2(c, f) << endl;
cout << DISPLACEMENT2(c, g) << endl;
cout << DISPLACEMENT2(c, h) << endl;
// cout << DISPLACEMENT2(c, i) << endl;
cout << DISPLACEMENT2(c, s) << endl;
cout << "sizeof(c) = " << sizeof(c) << endl;
cout << "sizeof(c.c) = " << sizeof(((c*) 0)->c) << endl;
cout << endl;
cout << DISPLACEMENT2(ccc, a) << endl;
cout << DISPLACEMENT2(ccc, b) << endl;
cout << DISPLACEMENT2(ccc, c) << endl;
cout << DISPLACEMENT2(ccc, d) << endl;
cout << DISPLACEMENT2(ccc, e) << endl;
cout << DISPLACEMENT2(ccc, f) << endl;
cout << DISPLACEMENT2(ccc, g) << endl;
//cout << DISPLACEMENT2(ccc, h) << endl;
cout << "sizeof(ccc) = " << sizeof(ccc) << endl;
cout << endl;
student s;
cout << sizeof(s.cc) << endl; //you
cout << sizeof(c) << endl;
cout << sizeof(ccc) << endl;
cout << "sizeof(d) = " << sizeof(d) << endl;
cout << DISPLACEMENT2(d, a) << endl;
cout << DISPLACEMENT2(d, b) << endl;
cout << DISPLACEMENT2(d, c) << endl;
cout << DISPLACEMENT2(d, d) << endl;
cout << DISPLACEMENT2(d, f) << endl;
cout << endl;
cout << endl;
cout << "sizeof(cc) = " << sizeof(cc) << endl;
cout << "sizeof(student) = " << sizeof(student) << endl;
cout << "sizeof(ccc) = " << sizeof(ccc) << endl;
cout << "sizeof(c) = " << sizeof(c) << endl;
cout << "sizeof(d) = " << sizeof(d) << endl;
cout << "sizeof(e) = " << sizeof(e) << endl;
cout << "sizeof(f) = " << sizeof(f) << endl;
cout << "sizeof(g) = " << sizeof(g) << endl;
cout << "Hello world!" << endl;
return 0;
}
补充:
首先要明确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/
//思考:若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
#include <iostream>
using namespace std;
struct cc {
char a;
char c[6];
char b;
};
struct student {
int a;
char b[20];
char c;
struct cc cc;
double d;
};
//用一个宏定义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 偏移地址二进制的最后三位:000;即8的倍数的地址对齐性;
// double偏移地址二进制的最后三位:000;即8的倍数的地址对齐性;
//总之,struct中基本类型成员的偏移地址时一定是sizeof(基本类型)的整数倍,
//自定义类型偏移地址的对齐性是任意的.
//推过这种方式,就能解释sizeof(struct s)不等于所有成员的sizeof的和。
// sizeof(struct s) 除了满足以上偏移地址对齐外,
// 是其大小为其基本类型成员的sizeof值最大的成员的sizeof值的整数倍
// 也就是说为最大的基本类型的sizeof值得整数倍。
#define FIND(s, member) (size_t)(&((*((s *)((void *)0))).member))
#define FIND1(s, member) (size_t)(&(*((s *)0)).member)
#define FIND2(s, member) (size_t)(&(((s *)0)->member))
#define DISPLACEMENT1(structure, member) (size_t) &((*((structure *)0)).member)
#define DISPLACEMENT2(structure, member) (size_t) &(((structure *)0)->member)
struct c {
char a; //1字节 [0, 0]
char c[5]; //5字节 [1, 5]
//char cc[2]; //填充2字节 [6, 7]
//8字节
int b; //12字节 [8, 11]
char d; //14字节 [12, 13] //填充一字节
short e; //16字节 [14, 15]
char f; //17字节 [16, 16]
char g; //18字节 [17, 17]
char h; //19字节 [18, 18]
//char i; //20字节 [19, 19]
short s; //24字节 [20, 23]
};
struct ccc {
char a; // 0
int b; // 4
char c[5]; // 8
char d; // 13
double e; // 16
char f; // 24
char g; // 25
//int h; // 28
};
struct d {
char a; //0
short b; //2
int c; //4
char d; //8
double f;//16
};
struct e {
char a; //0
double b; //8
char c; //16
}; //24
struct f {
char a; // 0
float b; // 4
char c; // 8
};
struct g {
char a;
short b;
char c;
};
// 12
int main()
{
cout << FIND(student, a) << endl;
cout << FIND(student, b) << endl;
cout << FIND(student, c) << endl;
cout << FIND(student, d) << endl;
cout << endl;
cout << FIND1(student, a) << endl;
cout << FIND1(student, b) << endl;
cout << FIND1(student, c) << endl;
cout << FIND1(student, d) << endl;
cout << endl;
cout << FIND2(student, a) << endl;
cout << FIND2(student, b) << endl;
cout << FIND2(student, c) << endl;
cout << FIND2(student, d) << endl;
cout << endl;
cout << DISPLACEMENT1(student, a) << endl;
cout << DISPLACEMENT1(student, b) << endl;
cout << DISPLACEMENT1(student, c) << endl;
cout << DISPLACEMENT1(student, d) << endl;
cout << endl;
cout << DISPLACEMENT2(student, a) << endl;
cout << DISPLACEMENT2(student, b) << endl;
cout << DISPLACEMENT2(student, c) << endl;
cout << DISPLACEMENT2(student, cc) << endl;
cout << DISPLACEMENT2(student, d) << endl;
cout << "sizeof(student) = " << sizeof(student) << endl;
cout << endl;
cout << DISPLACEMENT2(c, a) << endl;
cout << DISPLACEMENT2(c, b) << endl;
cout << DISPLACEMENT2(c, c) << endl;
cout << DISPLACEMENT2(c, d) << endl;
cout << DISPLACEMENT2(c, e) << endl;
cout << DISPLACEMENT2(c, f) << endl;
cout << DISPLACEMENT2(c, g) << endl;
cout << DISPLACEMENT2(c, h) << endl;
// cout << DISPLACEMENT2(c, i) << endl;
cout << DISPLACEMENT2(c, s) << endl;
cout << "sizeof(c) = " << sizeof(c) << endl;
cout << "sizeof(c.c) = " << sizeof(((c*) 0)->c) << endl;
cout << endl;
cout << DISPLACEMENT2(ccc, a) << endl;
cout << DISPLACEMENT2(ccc, b) << endl;
cout << DISPLACEMENT2(ccc, c) << endl;
cout << DISPLACEMENT2(ccc, d) << endl;
cout << DISPLACEMENT2(ccc, e) << endl;
cout << DISPLACEMENT2(ccc, f) << endl;
cout << DISPLACEMENT2(ccc, g) << endl;
//cout << DISPLACEMENT2(ccc, h) << endl;
cout << "sizeof(ccc) = " << sizeof(ccc) << endl;
cout << endl;
student s;
cout << sizeof(s.cc) << endl; //you
cout << sizeof(c) << endl;
cout << sizeof(ccc) << endl;
cout << "sizeof(d) = " << sizeof(d) << endl;
cout << DISPLACEMENT2(d, a) << endl;
cout << DISPLACEMENT2(d, b) << endl;
cout << DISPLACEMENT2(d, c) << endl;
cout << DISPLACEMENT2(d, d) << endl;
cout << DISPLACEMENT2(d, f) << endl;
cout << endl;
cout << endl;
cout << "sizeof(cc) = " << sizeof(cc) << endl;
cout << "sizeof(student) = " << sizeof(student) << endl;
cout << "sizeof(ccc) = " << sizeof(ccc) << endl;
cout << "sizeof(c) = " << sizeof(c) << endl;
cout << "sizeof(d) = " << sizeof(d) << endl;
cout << "sizeof(e) = " << sizeof(e) << endl;
cout << "sizeof(f) = " << sizeof(f) << endl;
cout << "sizeof(g) = " << sizeof(g) << endl;
cout << "Hello world!" << endl;
return 0;
}
补充:
首先要明确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/
相关文章推荐
- 目前国际经济局势不大明朗,大企业部署物联网有增无减
- 3402 数据结构实验之排序五:归并求逆序数
- forEach遍历小实例
- 【Leetcode】8. String to Integer (atoi)
- android DiskLruCache使用方法
- android studio 问题集
- Java添加中文到mysql乱码
- 20145325张梓靖 《信息安全系统设计基础》第13周学习总结
- 基础算法 01背包问题
- 查询几天以内的数据sql语句
- 基于用户的协同过滤(user-based collaborative filtering)
- 分享asp.net 网站部署一段时候后无法响应经验
- 389. Find the Difference#2(Done)
- 学习内容
- 《高胜算交易策略》读书笔记
- 50. Pow(x, n)
- 神经网络与深度学习(3):Backpropagation算法
- Linux电源管理-Runtime PM
- 1080. Graduate Admission (30)
- 郝斌的C语言基础 165,166 枚举