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(结构体)和内存对齐以及位域的更多相关文章

  1. C语言结构体的内存对齐问题

    在C语言开发当中会遇到这样的情况: #include <stdio.h> struct test { int a; char b; }; int main(int argc, const ...

  2. C语言 结构体的内存对齐问题与位域

    http://blog.csdn.net/xing_hao/article/details/6678048 一.内存对齐 许多计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地 ...

  3. 3.c语言结构体成员内存对齐详解

    一.关键一点 最关键的一点:结构体在内存中是一个矩形,而不是一个不规则形状 二.编程实战 #include <stdlib.h> #include <stdio.h> stru ...

  4. [转]C++结构体|类 内存对齐详解

    内存地址对齐,是一种在计算机内存中排列数据(表现为变量的地址).访问数据(表现为CPU读取数据)的一种方式,包含了两种相互独立又相互关联的部分:基本数据对齐和结构体数据对齐 . 为什么需要内存对齐?对 ...

  5. C语言结构体的字节对齐原则

    为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据 ...

  6. C语言结构体在内存中的存储情况探究------内存对齐

    条件(先看一下各个基本类型都占几个字节): void size_(){ printf("char类型:%d\n", sizeof(char)); printf("int类 ...

  7. 36深入理解C指针之---结构体的内存处理

    一.有关结构体的内存处理包括,结构体指针和结构体成员指针的内存分配.结构体成员的数据对齐.结构体的内存释放 1.定义:与自定义数据类型(结构体)有关的内存分配.大小和释放问题 2.特征: 1).用内存 ...

  8. 实验:使用GDB查看结构体在内存中的存储方式

    结构体在内存中的表示形式是怎么样的? 结构体在内存中和普通变量存储没有太大的区别. 首先我们看看,计算机如何读取普通变量:   普通变量例如int是占据4个字节,计算机读内存的时候会从起始地址开始读, ...

  9. C语言结构体变量字节对齐问题总结

    结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但 ...

随机推荐

  1. 机器学习技法:03 Kernel Support Vector Machine

    Roadmap Kernel Trick Polynomial Kernel Gaussian Kernel Comparison of Kernels Summary

  2. [SCOI 2016]背单词

    Description Lweb 面对如山的英语单词,陷入了深深的沉思,“我怎么样才能快点学完,然后去玩三国杀呢?”.这时候睿智 的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,他的计 ...

  3. [BZOJ 4403]序列统计

    Description 给定三个正整数N.L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量.输出答案对10^6+3取模的结果. Input 输入第一行包含一个整数T,表示数据组 ...

  4. [HAOI2007]分割矩阵

    题目描述 将一个a*b的数字矩阵进行如下分割:将原矩阵沿某一条直线分割成两个矩阵,再将生成的两个矩阵继续如此分割(当然也可以只分割其中的一个),这样分割了(n-1)次后,原矩阵被分割成了n个矩阵.(每 ...

  5. 無名(noname)

    [问题描述] 因为是蒯的题所以没想好名字,为什么要用繁体呢?去看<唐诗三百首>吧! 题意很简单,给你一个串,求他有多少个不同的子串,满足前缀为A,后缀为B. 需要注意的是,串中所有的字母都 ...

  6. HDU2256(矩阵)

    求(sqrt(2) + sqrt(3)) ^ 2n MOD 1024 强行盗图- -,这公式推得 .. #include <iostream> #include <cstdio> ...

  7. hdu 5430(几何)

    题意:求光在圆内反射n次后第一次返回原点的方案数 如果k和n-1可约分,则表明是循环多次反射方案才返回原点. #include <iostream> #include <cstrin ...

  8. Cookie 和 Session的基本使用

    cookie: 放在客户端上的键值对. 1.设置cookie obj = render(request,'index.html') obj.set_cookie('key','value') retu ...

  9. PTA 邻接矩阵存储图的深度优先遍历

    6-1 邻接矩阵存储图的深度优先遍历(20 分) 试实现邻接矩阵存储图的深度优先遍历. 函数接口定义: void DFS( MGraph Graph, Vertex V, void (*Visit)( ...

  10. 单页应用动态设置页面title

    1.适用场景:所有通过router路由的单页应用. 2.示例代码:本文以vue-router为例. 在router.js中: let router = new Router({ routes: [ { ...