sizeof(结构体)和内存对齐以及位域
Win32平台下的微软C编译器的对齐策略:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
备注:编译器在给结构体开辟空间时,首先找到结构体中最宽的基本数据类型,然后寻找内存地址能被该基本数据类型所整除的位置,作为结构体的首地址。将这个最宽的基本数据类型的大小作为上面介绍的对齐模数。
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;
备注:为结构体的一个成员开辟空间之前,编译器首先检查预开辟空间的首地址相对于结构体首地址的偏移是否是本成员的整数倍,若是,则存放本成员,反之,则在本成员和上一个成员之间填充一定的字节,以达到整数倍的要求,也就是将预开辟空间的首地址后移几个字节。
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节。
备注:结构体总大小是包括填充字节,最后一个成员满足上面两条以外,还必须满足第三条,否则就必须在最后填充几个字节以达到本条要求。
根据以上准则,在windows下,使用VC编译器,sizeof(T)的大小为8个字节。
而在GNU GCC编译器中,遵循的准则有些区别,对齐模数不是像上面所述的那样,根据最宽的基本数据类型来定。在GCC中,对齐模数的准则是:对齐模数最大只能是4,也就是说,即使结构体中有double类型,对齐模数还是4,所以对齐模数只能是1,2,4。而且在上述的三条中,第2条里,offset必须是成员大小的整数倍,如果这个成员大小小于等于4则按照上述准则进行,但是如果大于4了,则结构体每个成员相对于结构体首地址的偏移量(offset)只能按照是4的整数倍来进行判断是否添加填充。
看如下例子:
struct T
{
char ch;
double d ;
};
那么在GCC下,sizeof(T)应该等于12个字节。
如果结构体中含有位域(bit-field),那么VC中准则又要有所更改:
- 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
- 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
- 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式;
备注:当两字段类型不一样的时候,对于不压缩方式,例如:
struct N
{
char c:2;
int i:4;
};
依然要满足不含位域结构体内存对齐准则第2条,i成员相对于结构体首地址的偏移应该是4的整数倍,所以c成员后要填充3个字节,然后再开辟4个字节的空间作为int型,其中4位用来存放i,所以上面结构体在VC中所占空间为8个字节;而对于采用压缩方式的编译器来说,遵循不含位域结构体内存对齐准则第2条,不同的是,如果填充的3个字节能容纳后面成员的位,则压缩到填充字节中,不能容纳,则要单独开辟空间,所以上面结构体N在GCC或者Dev-C++中所占空间应该是4个字节。
- 如果位域字段之间穿插着非位域字段,则不进行压缩;
typedef struct
{
char c:2;
double i;
int c2:4;
}N3;
在GCC下占据的空间为16字节,在VC下占据的空间应该是24个字节。
- 整个结构体的总大小为最宽基本类型成员大小的整数倍。
#include <iostream>
using namespace std;
struct
{
bool a1;
int a2;
bool a3;
}A;
struct
{
int a1;
bool a2;
bool a3;
}B ;
struct
{
bool a2;
bool a3;
int a1;
}C ;
int main()
{ cout << sizeof(A) << " ";
cout << sizeof(B) << " ";
cout << sizeof(C) << " ";
}
输出:12 8 8
对齐模数的选择只能是根据基本数据类型,所以对于结构体中嵌套结构体,只能考虑其拆分的基本数据类型。而对于对齐准则中的第2条,确是要将整个结构体看成是一个成员,成员大小按照该结构体根据对齐准则判断所得的大小。
类对象在内存中存放的方式和结构体类似,这里就不再说明。需要指出的是,类对象的大小只是包括类中非静态成员变量所占的空间,如果有虚函数,那么再另外增加一个指针所占的空间即可。
sizeof(结构体)和内存对齐以及位域的更多相关文章
- C语言结构体的内存对齐问题
在C语言开发当中会遇到这样的情况: #include <stdio.h> struct test { int a; char b; }; int main(int argc, const ...
- C语言 结构体的内存对齐问题与位域
http://blog.csdn.net/xing_hao/article/details/6678048 一.内存对齐 许多计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地 ...
- 3.c语言结构体成员内存对齐详解
一.关键一点 最关键的一点:结构体在内存中是一个矩形,而不是一个不规则形状 二.编程实战 #include <stdlib.h> #include <stdio.h> stru ...
- [转]C++结构体|类 内存对齐详解
内存地址对齐,是一种在计算机内存中排列数据(表现为变量的地址).访问数据(表现为CPU读取数据)的一种方式,包含了两种相互独立又相互关联的部分:基本数据对齐和结构体数据对齐 . 为什么需要内存对齐?对 ...
- C语言结构体的字节对齐原则
为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据 ...
- C语言结构体在内存中的存储情况探究------内存对齐
条件(先看一下各个基本类型都占几个字节): void size_(){ printf("char类型:%d\n", sizeof(char)); printf("int类 ...
- 36深入理解C指针之---结构体的内存处理
一.有关结构体的内存处理包括,结构体指针和结构体成员指针的内存分配.结构体成员的数据对齐.结构体的内存释放 1.定义:与自定义数据类型(结构体)有关的内存分配.大小和释放问题 2.特征: 1).用内存 ...
- 实验:使用GDB查看结构体在内存中的存储方式
结构体在内存中的表示形式是怎么样的? 结构体在内存中和普通变量存储没有太大的区别. 首先我们看看,计算机如何读取普通变量: 普通变量例如int是占据4个字节,计算机读内存的时候会从起始地址开始读, ...
- C语言结构体变量字节对齐问题总结
结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但 ...
随机推荐
- ASP.NET Core 如何在运行Docker容器时指定容器外部端口
前面我写了一系列关于持续集成的文章,最终构建出来的镜像运行之后,应该会发现每次构建运行之后端口都变了,这对于我们来说是十分不方便的,所以我们可以通过修改docker compose的配置文件来完成我们 ...
- php array_multisort函数实现按某一字段对二维数组进行排序
在工作中碰到一个页面如表格似的展示多条数据,要求根据其中的修改时间对数据进行排序, 数据格式类似于 $a = array( 0=>array( editTime=>'' addTime=& ...
- codevs 2964 公共素数因数
提交地址:http://codevs.cn/problem/2964/ 2964 公共素数因数 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 白银 Silver 题解 ...
- Basic command and advice for memcached
Storage Commands set Most common command. Store this data, possibly overwriting any existing data. N ...
- 规约模式(Specification Pattern)
一.引言 最近在看一个项目的源码时(DDD),对里面的一些设计思想和设计思路有了一些疑问.当看到(Repository层)中使用了 spec.SatisfiedBy() 时,感觉有点懵.于是在项目中搜 ...
- ●BOZJ 2127 happiness
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2127 题解: 和 BZOJ 3984 建图类似(最小割模型).但是这个建图方法效率有点低.另 ...
- Codeforces Round #398 (div.2)简要题解
这场cf时间特别好,周六下午,于是就打了打(谁叫我永远1800上不去div1) 比以前div2的题目更均衡了,没有太简单和太难的...好像B题难度高了很多,然后卡了很多人. 然后我最后做了四题,E题感 ...
- APIO2017 懵逼记
Day -1: 移步http://www.cnblogs.com/juruolty/p/6854795.html Day 0: CTSC铁牌后,下一个就是APIO了. lmy,sxy,cxc,lh过来 ...
- mybatis下使用log4j打印sql语句和执行结果
转载自:https://www.cnblogs.com/jeevan/p/3493972.html 本来以为很简单的问题, 结果自己搞了半天还是不行; 然后google, baidu, 搜出来各种方法 ...
- 【集合框架】JDK1.8源码分析之HashMap(一) 转载
[集合框架]JDK1.8源码分析之HashMap(一) 一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化 ...