【C++ Primer】 神秘的 sizeof(union) 、sizeof(struct) 和内存对齐技术
来源:互联网 发布:class转java工具 编辑:程序博客网 时间:2024/06/06 02:54
转自:
http://blog.csdn.net/tianshuai1111/article/details/7576279
注意两点就可以了:
1. 起始地址一定是sizeof(type)的整数倍!!!!!!!
2. 调成最长类型的整数倍!!!!!!!!!!!
3. char arr[15]并不参与对齐
例如:以下的代码:
第1个c的地址是0, 第2个i的地址要调成4,第3个的地址是8,第4个double的地址本来是12,调成16,第5个地址是24,第6个是28,第7个是32,所以占用了36,要调成8的整数倍。。。所以是40。。。
#include<iostream>using namespace std;struct A { char c; int i; float f; double d; int *x; char *ch; short e;} a;#pragma pack(pop)int main(void){ A a; int sizea = sizeof(a); //40return 0;}
一,union:C/C++关键字 共用体(联合)
共用体的声明和共用体变量定义与结构十分相似。形式为:
- union 共用体名
- {
- 数据类型 成员名;
- 数据类型 成员名;
- ...
- } 变量名;
共用体表示几个变量共用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量.在union中,所有的共用体成员共用一个空间,并且同一时间只能储存其中一个成员变量的值。当一个共用体被声明时, 编译程序自动地产生一个变量, 其长度为联合中最大的变量长度的整数倍(特别注意数组)
例子一:
union foo{
int i;
char c;
double k;
};
sizeof(foo); //double最长占用8字节,所以union foo大小为8字节
例子二:
- union A
- {
- int a[5]; //20
- short b; //2
- double c; //8
- char p2; //1
- };
- struct B {
- int n; // 4字节
- A a; // 24字节
- char c[10]; // 10字节
- };
sizeof(A) ; //24 而不是20 ???
sizeof(B) ; //48 而不是???
对齐: 分配内存时,每个成员放在长度倍数位置,如果不够,补位对齐
补齐: 对整个结构变量的空间要求总长度一定是最长的成员的倍数,不够补齐不管是对齐还是补齐,最长的成员长度超过4时,以4计。
A实际占用内存大小为 20字节,但是要跟 8个字节的变量double的整数倍,对齐所以为 24;
由于A实际占用24字节,则可以想象B实际占用38字节,但A是8字节对齐的,所以int n和char c[10]也需要8字节对齐,总共8+24+16=48 字节。
例子三:
- union f
- {
- char s[10];
- int i;
- };
sizeof(f); // 12
解释:在这个union中,foo的内存空间的长度为12,是int型的3倍,而并不是数组的长度10。
若把int改为double,则foo的内存空间为16,是double型的两倍。
二,struct
具体说明见内存对齐例子
三,内存对齐
1)概念:“内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。
2)原因:
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因是:为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
3)对齐规则
每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。
规则:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
3、结合1、2可推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
pragma pack(1) 时候
1>数据成员对齐:
- #pragma pack(1)
- struct test_t
- {
- int a; /* int型, 长度4 > 1 按1对齐;起始offset=0 0%1=0;存放位置区间[0,3] */
- char b; /* char型, 长度1 = 1 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */
- short c; /* short型,长度2 > 1 按1对齐;起始offset=5 5%1=0;存放位置区间[5,6] */
- char d[6]; /* char型, 长度1 = 1 按1对齐;起始offset=7 7%1=0;存放位置区间[7,C] */
- };/*char d[6]要看成6个char型变量*/
sizeof(test_t) ; //输出为13
2>整体对齐
整体对齐系数 = min((max(int,short,char), 1) = 1
整体大小(size)=$(成员总大小) 按 $(整体对齐系数) 圆整 = 13 /*13%1=0*/
pragma pack(2) 时候
1>成员数据对齐
- #pragma pack(2)
- struct test_t {
- int a; /* int型,长度4 > 2 按2对齐;起始offset=0 0%2=0;存放位置区间[0,3] */
- char b; /* char型,长度1 < 2 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */
- short c; /* short型,长度2 = 2 按2对齐;起始offset=6 6%2=0;存放位置区间[6,7] */
- char d[6]; /* char型,长度1 < 2 按1对齐;起始offset=8 8%1=0;存放位置区间[8,D] */
- };
2> 整体对齐
整体对齐系数 = min((max(int,short,char), 2) = 2
整体大小(size)=$(成员总大小) 按 $(整体对齐系数) 圆整 = 14 /* 14%2=0 */
四,终极例子
入门例子一:
- union A
- {
- int t; //4
- short m; //2
- char p; //1
- };
- struct B
- {
- A a; //4
- double c; //8
- char p2; //1
- };
sizeof(B); // 24
B中采用double长度 8字节对齐方式,所以A在结构体B内 变成8字节。实际B占用 8+8+1=17。再填充成8的整数倍后位 24字节
变态例子二:
- struct B
- {
- union A
- {
- int t; //4
- short m; //2
- char p; //1
- } ;
- double c; //8
- char p2; //1
- };
sizeof(B); //16
如果你的第一反应是24那么你就躺着中枪了。想想为什么吧!!
4+8+1=13 最大类型 8的最小倍数为 16
附件:在GCC中示例代码
- #include "stdio.h"
- typedef struct BB
- {
- union AA //没有typedef
- {
- int t; //4
- short m; //2
- char p; //1
- } AA;
- double c; //8
- char p2; //1
- }BB;
- typedef union A //有typedef
- {
- int t; //4
- short m; //2
- char p; //1
- }A;
- typedef struct B
- {
- A a; //4
- double c; //8
- char p2; //1
- }B;
- int main()
- {
- printf("BB:%d\n",sizeof(BB));
- printf("B:%d\n",sizeof(B));
- return 0;
博主对"变态例子2"的理解有误.在那例子中,之所以B占用16个字节,是因为Union A并没有用来定义任何变量,所以不占用空间.B的实际大小是double的8+char的1=9,再补齐成8的倍数,结果是16.有试验证明:
- #include <iostream>
- using namespace std;
- struct B
- {
- union A
- {
- int t; //4
- short m; //2
- char p; //1
- } ;
- double c; //8
- char p2; //1
- };
- void main()
- {
- B myB;
- myB.c=9.9;
- myB.p2='x';
- cout<<sizeof(myB)<<endl; //输出16
- char* BytePoint=(char*)&myB; //将myB首字节的地址赋值给BytePoint变量
- cout<<*(double*)(BytePoint)<<endl; //将BytePoint开始的地址当成double类型输出,结果9.9
- cout<<*(char*)(BytePoint+8)<<endl;//将myB的第八个字节当成字符输出,结果是x
- }
- 神秘的 sizeof(union) 、sizeof(struct) 和内存对齐技术
- 神秘的 sizeof(union) 、sizeof(struct) 和内存对齐技术
- 【C++ Primer】 神秘的 sizeof(union) 、sizeof(struct) 和内存对齐技术
- 【C++ Primer】 神秘的 sizeof(union) 、sizeof(struct) 和内存对齐技术
- 【C++ Primer】 神秘的 sizeof(union) 、sizeof(struct) 和内存对齐技术
- sizeof(union) 、sizeof(struct) 和内存对齐技术
- sizeof union struct 内存对齐
- sizeof union struct 内存对齐
- union, struct , sizeof. 对齐
- 神秘的sizeof(union和struct的区别)
- sizeof (union) (struct) 内存对齐方式
- struct union数据对齐和sizeof大小
- sizeof(struct)和sizeof(union)
- strlen与sizeof区别(转载)以及struct,union的sizeof内存对齐等问题
- 自然对齐:sizeof struct, union
- sizeof union和struct
- C当中关于sizeof(struct)和sizeof(union)
- C语言中的sizeof(struct )和sizeof(union)
- 网络协议基本常识
- Recover Binary Search Tree
- 四、属性数据类型
- 六、游标
- 开始编程 Day 1
- 【C++ Primer】 神秘的 sizeof(union) 、sizeof(struct) 和内存对齐技术
- 回调函数
- Php面向对象 – 继承和重写
- 三、子查询、伪劣和常用函数
- awk的学习
- 黑马程序猿 正则表达公式的学习
- Oracle必知函数
- Cocos2dx在Linux编译出现未定义的引用
- Node【模块】之path