`
zjjzmw1
  • 浏览: 1366197 次
  • 性别: Icon_minigender_1
  • 来自: 开封
社区版块
存档分类
最新评论

union和struct 的sizeof 问题总结

    博客分类:
  • iOS
iOS 
阅读更多

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类型放在程序的开始或者最后。 

 

分享到:
评论

相关推荐

    sizeof 用法汇总 C和C++的语法

    6. `union`和`struct`的`sizeof`: - 在`union`中,`sizeof`返回的是所有成员中最大尺寸的那个。 - 在`struct`中,由于内存对齐,成员的排列可能会影响到结构体的总大小。通常,结构体会按照成员大小对齐,如果...

    个人整理sizeof()用法汇总

    `sizeof()`是一个C++语言中的运算符,用于计算数据类型或者...理解并熟练运用`sizeof()`是编程中提高效率和减少内存浪费的关键。通过掌握这些用法,开发者可以更好地控制程序的内存管理,编写更高效、更健壮的代码。

    详细解析C语言中的sizeof

    例如,假设有一个结构体包含`char`和`double`类型,即使`char`和`double`的总字节数为9,`sizeof(struct)`的结果可能是12,因为编译器可能会插入额外的空间使`double`类型对齐到4的倍数地址上。 #### 四、`sizeof`...

    深入了解C++ 结构体(struct)与共用体(union)

    在C++编程语言中,结构体(struct)和共用体(union)是两种基本的数据类型,它们都是从C语言继承而来的,并且C++对它们进行了扩充和改进。本文将深入了解C++ 结构体和共用体的相关资料,帮助大家更好地理解和学习...

    51CTO总结的C++经典面试题和答案

    在C++中,sizeof操作符可以用于获取数组、struct和union的大小。 九、面试题和答案 本资源还包括了多个面试题和答案,涵盖了C++的多方面知识点,包括变量的作用域、全局变量和局部变量、静态变量和普通变量、循环...

    sizeof使用说明

    2. **计算结构体、联合体等复杂类型的数据大小**:`sizeof`同样可以用于复合数据类型,如结构体(`struct`)或联合体(`union`)。这在内存分配和处理复杂数据结构时非常有用。 3. **测量动态分配内存的大小**:...

    2022年c语言面试题目101及最佳答案.docx

    最后,文章讨论了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。 ...

    《 C语言面试题大汇总》题集

    因此,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 ...

    C语言面试题大汇总之华为面试题1.doc

    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 的巨大作用,识别有经验的大神

    相比之下,有经验的开发者会巧妙地利用`struct`来解决这个问题。他们可能会定义一个包含报文类型的整型变量和一个`union`,`union`中包含三种不同的结构体,分别对应不同的报文格式。这样的设计允许直接以结构体的...

    嵌入式C精华经典教程

    - **union 的特点与应用**:了解如何利用 union 来节省内存空间和实现类型转换。 #### 五、嵌入式Linux移植与设备驱动 - **知识点13:基于ARM的嵌入式Linux移植** - **基本概念**:理解嵌入式Linux移植的基本...

    嵌入式系统编程修炼 arm linux c

    C/C++基础结构:struct与union #### 1.1 结构体(struct) 在C/C++中,`struct`是一种复合数据类型,用于组合不同类型的变量,以形成一个单一的数据结构。结构体中的成员可以是不同的数据类型,包括其他结构体。例如...

    华为微软等公司编程语言面试题.pdf

    2. 使用typedef关键字可以定义新的数据类型,例如union和struct。 函数 1. 函数的返回值可以是表达式的结果,例如返回a++的值。 2. 函数可以传递指针作为参数,例如multi函数传递了三个int类型的指针。 队列和栈 ...

    嵌入式面试资料(嵌入式程序员面试须知)

    当多个线程需要访问同一资源时,为了避免数据竞争和不一致性问题,需要通过同步机制来控制线程对资源的访问。同步通常涉及到锁(Locks)、信号量(Semaphores)等机制,确保同一时刻只有一个线程可以访问共享资源。 ...

Global site tag (gtag.js) - Google Analytics