`

【C++ Primer】 神秘的 sizeof(union) 、sizeof(struct) 和内存对齐技术

 
阅读更多

一,union:C/C++关键字 共用体(联合)

共用体的声明和共用体变量定义与结构十分相似。形式为:


共用体表示几个变量共用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量.在union中,所有的共用体成员共用一个空间,并且同一时间只能储存其中一个成员变量的值。当一个共用体被声明时, 编译程序自动地产生一个变量, 其长度为联合中最大的变量长度的整数倍(特别注意数组)

例子一:

union foo{

  int i;

  char c;

  double k;

  };


sizeof(foo); //double最长占用8字节,所以union foo大小为8字节

例子二: 


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 字节。

例子三:


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>数据成员对齐:


sizeof(test_t) ; //输出为13

2>整体对齐

   整体对齐系数 = min((max(int,short,char), 1) = 1

   整体大小(size)=$(成员总大小) 按 $(整体对齐系数) 圆整 = 13 /*13%1=0*/


pragma pack(2) 时候

1>成员数据对齐

  

  成员总大小=14

  2> 整体对齐

  整体对齐系数 = min((max(int,short,char), 2) = 2

  整体大小(size)=$(成员总大小) 按 $(整体对齐系数) 圆整 = 14 /* 14%2=0 */

四,终极例子

入门例子一:


sizeof(B); // 24

B中采用double长度 8字节对齐方式,所以A在结构体B内 变成8字节。实际B占用8+8+1=17。再填充成8的整数倍后位 24字节

变态例子二:

sizeof(B); //16

如果你的第一反应是24那么你就躺着中枪了。想想为什么吧!!


分享到:
评论

相关推荐

    C++Primer 笔记(不完整版)

    C++ Primer 是一本深入学习C++语言的经典教材,这份笔记虽然不完整,但涵盖了书本的前十个章节,提供了关于C++基础语法和核心概念的概述。 1. **变量与初始化** - C++中未初始化的变量使用是一个潜在的问题,因为...

    c++学习笔记_C++ Primer Plus

    23. 指针和数组:在某些情况下,指针和数组的使用方式相似,但要注意它们在内存和类型上的区别。 24. 循环语句:C++的循环语句包括`for`、`while`、`do-while`,与C语言相同。 25. 输入处理:`cin.get(char)`与`...

    《C++Primer3》阅读笔记

    《C++ Primer》是一本经典的C++学习书籍,这篇阅读笔记涵盖了多个重要的C++概念和技术。以下是笔记中提及的关键知识点的详细解释: 1. **浮点数类型选择**:在C++中,`double`类型的浮点数通常比`float`具有更高的...

    C++primer笔记

    本文对《C++ Primer》中的部分关键知识点进行了深入解析,涵盖了从基本数据类型、字符串处理到动态内存管理和类型转换等多个方面。这些知识点对于理解和掌握 C++ 编程语言的核心概念至关重要,同时也是实际开发中...

    嵌入式linux工程师面试题目C语言基础部分 问答题.doc

    - 《C++ Primer》:深入的C++教程,涵盖C++11及以上版本。 - 《深度探索C语言》:深入讲解C语言的底层机制。 关于C语言的评价,它简洁高效,但需要谨慎使用以避免陷阱。如果改造菜刀,虽然增加安全措施可能会使使用...

    数据结构专业课程设计方案报告约瑟夫环完整版.doc

    Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = value; newNode->next = NULL; return newNode; } void appendNode(Node** head, Node* newNode) { if (*head == NULL) { *head = newNode; ...

Global site tag (gtag.js) - Google Analytics