C++的内存模型

说明:

主要内容参照自Working Draft, Standard for Programming Language C++ - N4810的6.6.1 Memory model小节。

同时,一些概念的描述也参照了cppreference.com - memory_model

 

C++内存模型中的基本存储单元是字节。

一、字节:

字节是由连续的比特(bit)组成,其中比特的数量是由实现定义的。一个字节至少足以包含基本执行字符集的任何成员和Unicode UTF-8编码形式的八位编码单元(256 个相异值)。

注释:

基本源字符集由以下 96 个字符组成:
a) 5 个空白字符(空格 (space)、水平制表 (horizontal tab)、垂直制表 (vertical tab)、换页 (form feed)和 换行 (new-line))
b) 10 个数字字符,从 '0' 到 '9'
c) 52 个字母,从 'a' 到 'z' 以及从 'A' 到 'Z'
d) 29 个标点字符:_ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " ’

字节的最低有效位称为低位,最高有效位称为高位。

C++程序可用的内存由一个或多个连续字节序列组成。每个字节都有一个唯一的地址。

二、内存位置:

内存位置是:

  • 标量类型(算术类型、指针类型、枚举类型或 std::nullptr_t)的对象。
  • 或者是具有非零宽度的相邻位域(bit-fields)的最大序列。

注意:

语言的各种功能特性,例如引用和虚函数,可能引起额外的内存位置不能被程序访问,但它由实现者管理。

两个或多个执行线程可以访问单独的内存位置互不干扰。

三、位域和位字段:

1.基本构念:

bit-field:表示位字段。

bit-fields:表示位域:

  • 解释1,如下格式的成员声明的特定位字段来自N4810中11.3.9 Bit-fields的解释。

          标识符[可选] 属性说明符[可选] : 大小-常量表达式 花括号或'='初始值设定[可选]

  • 解释2,声明具有以位为单位的明确大小的类数据成员。相邻的位域成员可以打包成共享和跨过各个字节。来自cppreference.com-bit_field的解释。

2.内存访问:

  • 若位字段(bit-field)和相邻的非位字段(non-bit-field),它们位于不同的内存位置中,因此可以被两个执行线程并行地更新而不会产生干扰。
  • 这同样适用于两个位域,如果一个位域在嵌套的结构体中声明,而另一个不属于嵌套的结构体;或者两者被零长度位字段的声明分隔;或者两者被非位字段的声明分隔。
  • 如果两个位域之间的所有位字段也是非零宽度的位域,则同时更新同一结构中的两个位域是不安全的。

3.结构体示例说明:

struct A {
  char a;        // 内存位置 #1,成员变量a
  int b : 5,     // 内存位置 #2,位域b
      c : 11,    // 内存位置 #2 (延续),位域c
        : 0,
      d : 8;     // 内存位置 #3,位域d
  struct {
    int ee : 8;  // 内存位置 #4,位域ee
  } e;
  short f;       // 内存位置 #5,成员变量f
} obj;           // 对象 'obj' 由 5 个分离的内存位置组成

该结构体包含五个独立的内存位置:成员a,位域d(它前面有零长度位字段的声明,分隔成独立的内存位置),位字段e.ee和成员f,它们每个有独立的内存位置,并且可以同时修改而不会相互干扰。

位域b和位域c(b和c两个位域之间没有其他位字段,也等价于它们之间的所有位字段是非零宽度的位域)一起构成第五个内存位置。

位域b和位域c不能同时修改,但例如,位域b和成员a可以同时被修改。

4.内存位置示例说明:

#include <iostream>
using namespace std;

struct A {
  char a;        // 内存位置 #1,成员变量a
  int b : 5,     // 内存位置 #2,位域b
      c : 11,    // 内存位置 #2 (延续),位域c
        : 0,
      d : 8;     // 内存位置 #3,位域d
  struct {
    int ee : 8;  // 内存位置 #4,位域ee
  } e;
  short f;       // 内存位置 #5,成员变量f
} obj;           // 对象 'obj' 由 5 个分离的内存位置组成

int main()
{
  cout << "sizeof(obj) is " << sizeof(obj) << endl;
  cout << "obj.a memory location is " << (void*)&obj.a << endl;
  //cout << "obj.b memory location is " << (void*)&obj.b << endl;
  // error: attempt to take address of bit-field structure member ‘A::b’
  cout << "obj.e memory location is " << (void*)&obj.e << endl;
  //cout << "obj.e.ee memory location is " << (void*)&obj.e.ee << endl;
  cout << "obj.f memory location is " << (void*)&obj.f << endl;

  return 0;
}

编译并运行,输出的结果如下:

sizeof(obj) is 16
obj.a memory location is 0x6011a0
obj.e memory location is 0x6011a8
obj.f memory location is 0x6011ac

从输出结果来看,编译器默认以4字自对齐的,原因应该是常用的寄存器为32bit,按4字节的方式读取,程序运行的效率看起来是最高的。

我们也可以推测出b,c,d的内存位置:obj.b和obj.c的内存位置是0x6011a4,obj.d的内存位置是0x6011a6。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值