1. 位域:

1. 在C中,位域可以写成这样(注:位域的数据类型一律用无符号的,纪律性)。
 struct bitmap
{
  unsigned a : ;
  unsigned b : ;
  unsigned c : ;
}bit;
  sizeof(bitmap) == 4;(整个struct的大小为4,因为位域本质上是从一个数据类型分出来的,在我们的例子中数据类型就是unsigned,大小为4,并且位域也是满足C和C++的结构体内存对齐原则的,等下我们会说到)。
2. 当然了位域也可以有空域。
 struct bitmap
{
  unsigned a:;
  unsigned :; /*空域*/
  unsigned b:; /*从下一单元开始存放*/
  unsigned c:;
}
sizeof(bitmap) == ;
3. 在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。这里我们可以看到空域的作用是填充数据类型的剩下的位置,有时候我们只是想调整一下内存分配,则我们可以使用无名位域:
 struct bitmap
{
  unsigned a:;
  unsigned :;
  unsigned b:;
  unsigned c:;
};
sizeof(bitmap) == ;
4. 如果一个位域的位的分配超过了该类型的位的总数,则从下一个单元开始继续分配,这个很好理解:
 struct bitmap
{
  unsigned a : ;
  unsigned b : ;
  unsigned c : ;
};
sizeof(bitmap) == ;
  注意这个位域的大小是12而不是8,说明如果超了大小是立马从下一个单元开始分配而不是cast在后面。
 
5. C++的位域:
  由于C++有类,所以呢位域可以写进类里面,很简单比如:
 class Demo
{
  unsigned mode : ;
  unsigned modeifed : ;
  unsigned protA : ;
  unsigned protB : ;
public:
...
};
  另外就是需要注意的是,取地址运算符不能作用于位域,所以任何指针都无法指向类的位域,访问位域的方法和访问类的成员的方法一样,这里就不多说了。
 
2. 内存对齐:

1. 说到位域就不得说下内存对齐的东西,其实内存对齐也很简单,只是不同的编译器实现不一样,至于为什么要内存对齐,这个要从CPU的基本工作原理说起,但是首先要明白,无论我们是否内存对齐,CPU大多数情况都是能正常工作的(前提:对于大多数IA32指令都可以这么说,但是部分指令,如SSE多媒体指令这些就不行,这些指令有特殊内存对齐要求,比如16字节对齐,任何不满足内存对齐的地址访问储存器都是会导致异常,对于这些指令,编译器必须在编译的时候采取强制内存对齐)。
 
  实现内存对齐可以提高CPU的性能,比如处理器能一次取出8个字节,这个时候必须要求数据地址要8字节对齐,这个是和CPU和储存器的外围电路决定的,在内存对齐的情况下,CPU从储存器取出这8个字节只需要一个时钟周期,但是如果这个地址不是8字节对齐,那么CPU可能就需要两个时钟周期才能取出这8个字节。
  对于IA32,每个栈帧都惯例16字节对齐,编译器一般也会那么做,但是对于数据类型不同的编译器表现可能不一样,对于Windows(VC编译器),任何K字节的基本对象的地址都必须是K的倍数(比如对于int,必须4字节对齐,对于double,必须8字节对齐),这很大程度上提高了储存器和CPU的工作性能,但是对存储空间的浪费比较严重;对于Linux,惯例是8字节数对齐4字节边界(比如double可以4字节对齐)。对于Windows好Linux,数据类型long double都有4字节对其的要求,对于GCC,long double分配12字节(虽然它只占10字节大小)。
  所以我们有一般规则(在知乎找了个例子):
 struct X
{
  char a;
  float b;
  int c;
  double d;
  unsigned e;
};
sizeof(X) == ;
  内存对齐状况应该是下面这个样子:
 struct X
{
  char a; // 1 bytes
  char padding1[]; // 3 bytes
  float b; // 4 bytes
  int c; // 4 bytes
  char padding2[]; // 4 bytes
  double d; // 8 bytes
  unsigned e; // 4 bytes
  char padding3[]; // 4 bytes
};
sizeof(X) == ;
  (其中最后的4个字节的填充是因为规则4,看下面)。
 
2. 如果自定义数据类型含有位域,则内存对齐满足以下原则:
  1. 如果相邻的位域的数据类型相同,则按照分配位的大小来,详情看我上面写的位域的第5个情况。
  2. 如果相邻的位域的数据类型不相同,则不同编译器实现不一样,有些编译器选择不压缩。
  3. 如果位域不连续,中间含非位域,则按标准数据类型大小划分,比如:
 struct bitmap
{
  unsigned a : ;
  int b;
  unsigned c : ;
};
sizeof(bitmap) == ;
3. 另外可以通过添加#pragma pack(n)来强制改变内存分配情况,比如在VC编译器中:
 struct bitmap
{
  unsigned a;
  double c;
};
sizeof(bitmap) == ;
  加了#pragma pack(4),则强制内存对齐4字节,再测试下其大小:
 #pragma pack(4)
struct bitmap
{
  unsigned a;
  double c;
};
sizeof(bitmap) == ;
  当然,如果#pragma pack(n)的n大于本身数据类型的宽度,则按数据类型的宽度来分配:
 struct bitmap
{
  double c;
  int k;
  int m;
};
sizeof(bitmap) == !=
4. 自定义类型(C结构体,C++聚合类)的最后的内存对齐,是按照自定义类型内的最大类型的宽度来的,比如上面那个例子去掉int m:
 struct bitmap
{
  double c;
  int k;
};
sizeof(bitmap) ==
  必须以double进行8字节对齐(VC编译器)。
 
5. 对于C++如果类内有虚函数,则如果存在虚函数,则需要添加一个指针的大小(因为需要一个指针指向虚函数指针表,注意如果存在多个虚函数,也只有一个指向虚函数表指针),比如在32位系统则为4字节,在64位则为8字节。
 class Test
{
public:
virtual void Hi(); int c;
double d;
};
sizeof(Test) == (IA32)或者 (x86-)
  特别的,在C++内,空类大小为1(C++不允许0的内存空间)。
class Test
{
};
sizeof(Test) == ;
6. 如果一个类(结构体)A内嵌套着另一个类(结构体)B,则B按B内的最大类型的方式对齐,A的对齐要考虑B(总大小的对齐要考虑B的最大类型)
 class A
{
double c;
public:
class B
{
int i;
double c;
}b;
int d;
};
sizeof(A) == sizeof(A::B) ==

7. C++的类静态成员不会被sizeof计算,这个要注意:

class C
{
public:
static char b;
static int *c;
};

sizeof(C)的结果是1

 

C++位域和内存对齐问题的更多相关文章

  1. C/C++: C++位域和内存对齐问题

    1. 位域: 1. 在C中,位域可以写成这样(注:位域的数据类型一律用无符号的,纪律性). struct bitmap { unsigned a : ; unsigned b : ; unsigned ...

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

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

  3. 解析C语言结构体对齐(内存对齐问题)

    C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.内容虽然很基础,但一不小心就会弄错.写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的 ...

  4. struct内存对齐1:gcc与VC的差别

    struct内存对齐:gcc与VC的差别 内存对齐是编译器为了便于CPU快速访问而采用的一项技术,对于不同的编译器有不同的处理方法. Win32平台下的微软VC编译器在默认情况下采用如下的对齐规则:  ...

  5. 内存对齐-C语言struct内存占用问题

    转1个写的比较全面的. http://hubingforever.blog.163.com/blog/static/17104057920122256134681/ 本文编辑整理自:http://hi ...

  6. C/C++中的内存对齐 C/C++中的内存对齐

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

  7. C语言内存对齐(2)

    前两天参加了360测试实习生的笔试,碰到了一个有关c语言内存对齐的题目,回来后实现了一下,下面是代码: #include <stdio.h> #include <stdlib.h&g ...

  8. C++内存对齐总结

    大家都知道,C++空类的内存大小为1字节,为了保证其对象拥有彼此独立的内存地址.非空类的大小与类中非静态成员变量和虚函数表的多少有关. 而值得注意的是,类中非静态成员变量的大小与编译器内存对齐的设置有 ...

  9. C/C++ 知识点1:内存对齐

    预备知识:基本类型占用字节 在32位操作系统和64位操作系统上,基本数据类型分别占多少字节呢? 32位操作系统: char : 1    int :4    short : 2    unsigned ...

随机推荐

  1. 002--linux基础命令

    退出终端命令:exit 关闭Linux系统的命令:init 0 切换虚拟终端的方法:Ctrl+Alt+F[1-6] who命令 :查看有多少个终端打开着 whoami命令:获取当前用户名 date命令 ...

  2. HDOJ2955 0/1背包的价值和重量

    [hdoj2955] 1.概率问题: 计算逃跑率,但是要变成相×的 2.背包处理问题 然后因为率不能作为那个重量,所以价值作为重量,求一个在每个价值下的最大的逃跑率,然后在给定的逃跑率下面,来一个su ...

  3. PTA 计算平均值

    现在为若干组整数分别计算平均值. 已知这些整数的绝对值都小于100,每组整数的数量不少于1个,不大于20个. 输入格式:首先输入K(不小于2,不大于20).接下来每一行输入一组数据(至少有一组数据), ...

  4. React的深入浅出

    react组件重新渲染有两种途径:1.自身调用setState:2.父组件传入新的props.3.但这两种途径都不会必然调用render而引起重新渲染, 都会先经过shouldComponentUpd ...

  5. PJzhang:左耳朵耗子-陈皓

    猫宁!!! 参考链接:https://coolshell.cn/haoel 左耳朵耗子原名陈皓,那个是他的网络ID,在我眼中是个值得尊敬的程序员,虽然我对他真人没什么了解. 这是他博客的自我介绍: 2 ...

  6. 笔记-JavaWeb学习之旅

    junit单元测试 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值 白盒测试:需要些代码,关注程序具体的执行流程 Junit使用: 白盒测试 ​ 步骤: 定义一个测试类(测试用例) 定义 ...

  7. POJ 2104 K-th Number && 洛谷 P3834 【模板】可持久化线段树 1(主席树)

    我惊奇的发现这两道题一模一样 题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个整数构成的序列,将对于指定的闭区间查询 ...

  8. vs2015未能正确加载“ProviderPackage”包

    出现以下错误的解决方案 ---------------------------Microsoft Visual Studio---------------------------未能正确加载“Prov ...

  9. Qt容器类之二:迭代器

    一.介绍 遍历一个容器可以使用迭代器(iterators)来完成,迭代器提供了一个统一的方法来访问容器中的项目.Qt的容器类提供了两种类型的迭代器:Java风格迭代器和STL风格迭代器.如果只是想按顺 ...

  10. 从一个n位数中选出m位按顺序组成新数并使其最大 || Erasing and Winning UVA - 11491

    就是从n位数中取出n-d个数字按顺序排成一排组成一个新数使得其最大 算法: 从前往后确定每一位.找第i位时,要求后面留下d-i位的空间, 因此第i位应该从第i-1位原来位置+1到第d+i位寻找 用线段 ...