union u { double a; int b; };
union u2 { 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中才有这样的差异。
所以,在自己定义结构体的时候,如果空间紧张的话,最好考虑对齐因素来排列结构体里的元素。
10、不要让double干扰你的位域
在结构体和类中,可以使用位域来规定某个成员所能占用的空间,所以使用位域能在一定程度上节省结构体占用的空间。不过考虑下面的代码:
struct s1 { int i: 8; int j: 4; double b; int a:3; };
struct s2 { int i; int j; double b; int a; };
struct s3 { int i; int j; int a; double b; };
struct s4 { int i: 8; int j: 4; int a:3; double b; };
cout<<sizeof(s1)<<endl; // 24 cout<<sizeof(s2)<<endl; // 24 cout<<sizeof(s3)<<endl; // 24 cout<<sizeof(s4)<<endl; // 16 |
可以看到,有double存在会干涉到位域(sizeof的算法参考上一节),所以使用位域的的时候,最好把float类型和double类型放在程序的开始或者最后。
分享到:
相关推荐
6. `union`和`struct`的`sizeof`: - 在`union`中,`sizeof`返回的是所有成员中最大尺寸的那个。 - 在`struct`中,由于内存对齐,成员的排列可能会影响到结构体的总大小。通常,结构体会按照成员大小对齐,如果...
`sizeof()`是一个C++语言中的运算符,用于计算数据类型或者...理解并熟练运用`sizeof()`是编程中提高效率和减少内存浪费的关键。通过掌握这些用法,开发者可以更好地控制程序的内存管理,编写更高效、更健壮的代码。
例如,假设有一个结构体包含`char`和`double`类型,即使`char`和`double`的总字节数为9,`sizeof(struct)`的结果可能是12,因为编译器可能会插入额外的空间使`double`类型对齐到4的倍数地址上。 #### 四、`sizeof`...
在C++编程语言中,结构体(struct)和共用体(union)是两种基本的数据类型,它们都是从C语言继承而来的,并且C++对它们进行了扩充和改进。本文将深入了解C++ 结构体和共用体的相关资料,帮助大家更好地理解和学习...
在C++中,sizeof操作符可以用于获取数组、struct和union的大小。 九、面试题和答案 本资源还包括了多个面试题和答案,涵盖了C++的多方面知识点,包括变量的作用域、全局变量和局部变量、静态变量和普通变量、循环...
2. **计算结构体、联合体等复杂类型的数据大小**:`sizeof`同样可以用于复合数据类型,如结构体(`struct`)或联合体(`union`)。这在内存分配和处理复杂数据结构时非常有用。 3. **测量动态分配内存的大小**:...
最后,文章讨论了typedef union和struct的使用,例如typedef union {long i; int k[5]; char c;} DATE; struct data {int cat; DATE cow; double dog;} too; DATE max;的sizeof(struct date)+sizeof(max)的值为52。 ...
因此,sizeof(struct data)和sizeof(DATE)的结果不同。 8. 队列和栈的区别 队列是先进先出,而栈是后进先出。 9. 代码的输出结果 printf("%d",sizeof(struct data)+sizeof(max)); 的执行结果是52。 这些知识点...
typedef struct _EPROCESS_XP_SP3 // 107 elements, 0x260 bytes (sizeof) { /*0x000*/ struct _KPROCESS_XP_SP3 Pcb; // 29 elements, 0x6C bytes (sizeof) /*0x06C*/ struct _EX_PUSH_LOCK ProcessLock; // 5 ...
7. struct和union的区别 union是变量公用空间,struct是每个变量分开占用空间。例如,typedef union{long i; int k[5]; char c;} DATE; struct data{ int cat; DATE cow; double dog;} too; DATE max; printf("%d",...
相比之下,有经验的开发者会巧妙地利用`struct`来解决这个问题。他们可能会定义一个包含报文类型的整型变量和一个`union`,`union`中包含三种不同的结构体,分别对应不同的报文格式。这样的设计允许直接以结构体的...
- **union 的特点与应用**:了解如何利用 union 来节省内存空间和实现类型转换。 #### 五、嵌入式Linux移植与设备驱动 - **知识点13:基于ARM的嵌入式Linux移植** - **基本概念**:理解嵌入式Linux移植的基本...
C/C++基础结构:struct与union #### 1.1 结构体(struct) 在C/C++中,`struct`是一种复合数据类型,用于组合不同类型的变量,以形成一个单一的数据结构。结构体中的成员可以是不同的数据类型,包括其他结构体。例如...
2. 使用typedef关键字可以定义新的数据类型,例如union和struct。 函数 1. 函数的返回值可以是表达式的结果,例如返回a++的值。 2. 函数可以传递指针作为参数,例如multi函数传递了三个int类型的指针。 队列和栈 ...
当多个线程需要访问同一资源时,为了避免数据竞争和不一致性问题,需要通过同步机制来控制线程对资源的访问。同步通常涉及到锁(Locks)、信号量(Semaphores)等机制,确保同一时刻只有一个线程可以访问共享资源。 ...