考虑下面问题:(默认对齐方式)
union u { double a; int b; };
unionu2 { char a[13]; int b; };
union u3 { char a[13]; char b; };
cout<<sizeof(u)<<endl; // 8 cout<<sizeof(u2)<<endl; // 16 cout<<sizeof(u3)<<endl; // 13 |
都知道union的大小取决于它所有的成员中,占用空间最大的一个成员的大小。所以对于u来说,大小就是最大的double类型成员a了,所以sizeof(u)=sizeof(double)=8。但是对于u2和u3,最大的空间都是char[13]类型的数组,为什么u3的大小是13,而u2是16呢?关键在于u2中的成员int b。由于int类型成员的存在,使u2的对齐方式变成4,也就是说,u2的大小必须在4的对界上,所以占用的空间变成了16(最接近13的对界)。
结论:复合数据类型,如union,struct,class的对齐方式为成员中对齐方式最大的成员的对齐方式。
顺便提一下CPU对界问题,32的C++采用8位对界来提高运行速度,所以编译器会尽量把数据放在它的对界上以提高内存命中率。对界是可以更改的,使用#pragma pack(x)宏可以改变编译器的对界方式,默认是8。C++固有类型的对界取编译器对界方式与自身大小中较小的一个。例如,指定编译器按2对界,int类型的大小是4,则int的对界为2和4中较小的2。在默认的对界方式下,因为几乎所有的数据类型都不大于默认的对界方式8(除了long double),所以所有的固有类型的对界方式可以认为就是类型自身的大小。更改一下上面的程序:
#pragma pack(2) union u2 { char a[13]; int b; };
union u3 { char a[13]; char b; }; #pragma pack(8)
cout<<sizeof(u2)<<endl; // 14 cout<<sizeof(u3)<<endl; // 13 |
由于手动更改对界方式为2,所以int的对界也变成了2,u2的对界取成员中最大的对界,也是2了,所以此时sizeof(u2)=14。
结论:C++固有类型的对界取编译器对界方式与自身大小中较小的一个。
9、struct的sizeof问题
因为对齐问题使结构体的sizeof变得比较复杂,看下面的例子:(默认对齐方式下)
struct s1 { char a; double b; int c; char d; };
struct s2 { char a; char b; int c; double d; };
cout<<sizeof(s1)<<endl; // 24 cout<<sizeof(s2)<<endl; // 16 |
同样是两个char类型,一个int类型,一个double类型,但是因为对界问题,导致他们的大小不同。计算结构体大小可以采用元素摆放法,我举例子说明一下:首先,CPU判断结构体的对界,根据上一节的结论,s1和s2的对界都取最大的元素类型,也就是double类型的对界8。然后开始摆放每个元素。
对于s1,首先把a放到8的对界,假定是0,此时下一个空闲的地址是1,但是下一个元素d是double类型,要放到8的对界上,离1最接近的地址是8了,所以d被放在了8,此时下一个空闲地址变成了16,下一个元素c的对界是4,16可以满足,所以c放在了16,此时下一个空闲地址变成了20,下一个元素d需要对界1,也正好落在对界上,所以d放在了20,结构体在地址21处结束。由于s1的大小需要是8的倍数,所以21-23的空间被保留,s1的大小变成了24。
对于s2,首先把a放到8的对界,假定是0,此时下一个空闲地址是1,下一个元素的对界也是1,所以b摆放在1,下一个空闲地址变成了2;下一个元素c的对界是4,所以取离2最近的地址4摆放c,下一个空闲地址变成了8,下一个元素d的对界是8,所以d摆放在8,所有元素摆放完毕,结构体在15处结束,占用总空间为16,正好是8的倍数。
这里有个陷阱,对于结构体中的结构体成员,不要认为它的对齐方式就是他的大小,看下面的例子:
struct s1 { char a[8]; };
struct s2 { double d; };
struct s3 { s1 s; char a; };
struct s4 { s2 s; char a; };
cout<<sizeof(s1)<<endl; // 8 cout<<sizeof(s2)<<endl; // 8 cout<<sizeof(s3)<<endl; // 9 cout<<sizeof(s4)<<endl; // 16; |
s1和s2大小虽然都是8,但是s1的对齐方式是1,s2是8(double),所以在s3和s4中才有这样的差异。
所以,在自己定义结构体的时候,如果空间紧张的话,最好考虑对齐因素来排列结构体里的元素。
C代码:
- struct{
- intn;
- chars[10];
- union{
- inta[5];
- charb;
- doublec;
- }u_a;
- }b;
结论:struct 里面的元素是顺序存储的,每个元素占用的字节数根据对齐字节数N(struct 里占用字节最多的元素与CPU对齐字节数中较小的一个)进行调整.如果从左至右M个元素加起来的字节数大于N,则按从右至左舍去K个元素直至M-K个元素加起来的字节数小于等于N,如果等于N则不用字节填充,小于N则把M-K-1的元素填充直至=N.
分享到:
相关推荐
1. 数据成员对齐规则:结构体(struct)或联合(union)的数据成员,第一个数据成员放在 offset 为 0 的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是...
内存对齐是C语言中一个重要的概念,它与结构体(struct)和联合体(union)的内存布局密切相关。在计算机系统中,为了访问速度和硬件限制,数据往往需要按照一定的规则存储在内存中。如果数据的起始地址符合某个特定值...
规则 1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为 0 的地方,以后每个数据成员的对齐按照#pragma pack 指定的数值和这个数据成员自身长度中,比较小的那个进行...
从给定的文件信息来看,标题与描述指向的是关于人际关系在个人成功中的作用,而标签与部分内容则涉及到了计算机科学领域中的概念,如"sizeof"、"内存对齐"、"结构体"和"联合体"。这似乎是一个混合了不同主题的信息...
6. `union`和`struct`的`sizeof`: - 在`union`中,`sizeof`返回的是所有成员中最大尺寸的那个。 - 在`struct`中,由于内存对齐,成员的排列可能会影响到结构体的总大小。通常,结构体会按照成员大小对齐,如果...
例如,假设有一个结构体包含`char`和`double`类型,即使`char`和`double`的总字节数为9,`sizeof(struct)`的结果可能是12,因为编译器可能会插入额外的空间使`double`类型对齐到4的倍数地址上。 #### 四、`sizeof`...
`sizeof()`是一个C++语言中的运算符,用于计算数据类型或者变量所占据的内存空间的大小,单位通常是字节。这个运算符对于理解和优化代码内存使用是非常有用的。下面将详细介绍`sizeof()`的一些主要用法。 1. **与`...
在这里就分享两条开发中曾经忽略的问题:1、Union(联合体)的字节对齐先看代码:#pragma pack(4)struct com{ union { double dTest; int nTest; char szTest[14]; }; char chTest1; char chTest2;};#pragma...
在这个特定的问题中,我们关注的是`sizeof`在结构体(struct)上的应用,特别是在Linux环境下的行为。 首先,让我们分析给定的代码示例: ```c struct s { char ch, *ptr; union { short a, b; unsigned int c...
### C语言结构体内存对齐详解 在C语言中,结构体是一种复合数据类型,它允许程序员将不同类型的变量组织在一起作为一个单元。本篇文章将详细解释C语言中的结构体内存对齐原理,并通过一个具体的例子来说明如何计算...
这意味着,`union`中的所有成员共享相同的内存空间,但一次只能存储其中一个成员的值。例如: ```c union { struct structA packetA; struct structB packetB; struct structC packetC; }; ``` 在这个例子中,`...
与struct相比,最显著的区别是union的数据成员共享同一段内存,以达到节省空间的目的。 下面是一个使用了共用体的C++程序: ```cpp #include using namespace std; union testunion{ char c; int i; }; int ...
- 使用`union`和`struct`结合的方式可以在不增加额外内存负担的情况下支持多态性。 6. **struct在嵌入式编程中的应用**: - 在嵌入式编程中,由于资源有限,`struct`可以用于精确控制内存使用,避免不必要的内存...
- 对于联合体(union),所有成员共享同一块内存,`sizeof`返回最大的成员的大小。在题目中的`union V`中,`v.c = 100`后,`v.x.s3`的值为3,因为`100`的二进制表示中,最后3位为11,放入`s3`中。 3. 空类与虚函数...
结构体的成员在内存中的排列可能会受到内存对齐规则的影响,导致实际占用的内存可能大于各成员之和。例如,`sizeof`操作符用于计算结构体的总大小。 10. **实例分析**: 例7-1.c展示了如何计算结构体`regist`的...
例如,`struct student` 占用的总大小是20(name)+ 1(sex)+ 4(num)+ 12(score)+ 30(addr)= 67个字节,但由于内存对齐的原因,实际占用空间可能是68或72字节,具体取决于编译器和平台的内存对齐策略。...