当前位置: 首页 > news >正文

【C++内存管理、底层管理,引用和指针、X86X64】

目录

一、X86 X64

常见误解澄清

二、栈和堆的区别

三、sizeof应用

1. 对数组名使用 sizeof

2. 对指针使用 sizeof

四、结构体的内存对齐

五、自增自减底层

六、引用与指针的区别

七、函数在什么情况下能用引用的方式返回地址?

可以安全返回引用的场景

❌ 绝对不能返回引用的场景


一、X86 X64

核心区别表

特性X86 (32位)X64 (64位)
虚拟地址空间4 GB (2^32)16 EB (2^64),实际用 256 TB
物理内存支持最大 4 GB理论上 16 EB,实际主板支持几十到几百 GB
指针大小4 字节8 字节
通用寄存器8 个 (eax, ebx, ecx, edx, esi, edi, ebp, esp)16 个 (rax, rbx, ... + r8-r15)
寄存器宽度32 位64 位
单次处理数据4 字节8 字节
程序兼容性不能在 64 位系统运行 16 位程序可运行 32 位程序(通过兼容层)

为什么X86叫32位系统,X64叫64位系统呢?

因为X86,它的地址总线是32根,最多可以访问2的32次方字节,大约是4GB,而X64是地址总线是64根,最多访问2的64次方字节就是约等于16EB

它们俩的最本质区别就是内存的寻址能力。

在32位系统中。单个程序最多使用2到3GB。 在64位系统中。支持256 TB。或者更多。

他们俩还有一个差异是数据类型大小差异。

数据类型X86 (32位)X64 (64位)
char11
short22
int44
long48(Windows: 4)
long long88
float44
double88
void*(指针)48
size_t48

特别注意:Linux 上long是 8 字节,Windows 上long是 4 字节(保持兼容性)

常见误解澄清

  1. 64位系统一定比32位快?

    • 不一定。指针变大导致缓存压力增加,某些程序反而变慢

    • 但更多寄存器和 64位运算有明显优势

  2. 64位系统不能运行32位程序?

    • 可以,通过兼容层支持

  3. long 在64位一定是8字节?

    • 不!Windows 上 long 仍是4字节

    • 可移植代码应使用int32_tint64_t等固定大小类型

二、栈和堆的区别

1.先了解内存布局

高地址 +------------------+ | 栈 (Stack) | ← 向下增长(向低地址) | (函数调用、局部变量) | +------------------+ | ↓ | | 空闲空间 | | ↑ | +------------------+ | 堆 (Heap) | ← 向上增长(向高地址) | (动态分配) | +------------------+ | 未初始化数据段 | | (BSS Segment) | +------------------+ | 已初始化数据段 | | (Data Segment) | +------------------+ | 代码段/只读区 | | (Text Segment) | +------------------+ 低地址

堆和栈的核心区别主要在他们的管理方式,分配速度和生命周期

  1. 栈他是有编译器自动管理,堆是由程序员手动管理malloc free或者是new,delete。

  2. 栈他的分配速度非常快,只需要移动指针。 堆的分配速度比较慢,它是因为需要找空闲块,处理碎片。

  3. 栈他的生命周期是作用域结束之后自动去释放,堆是需要去手动释放。

  4. 栈的分配方向是从高地址向低地址向下增长。堆的分配方向是从低地址向高地址向上增长。

  5. 栈他主要存放的是局部变量函数参数返回地址,堆主要存放的是动态分配的对象,数据。

  6. 栈他有可能会有一些栈溢出的越界风险,堆的话它可能会有内存泄漏,野指针等越界风险。

int * r=&a;星号代表修饰符

三、sizeof应用

编译时确定sizeof编译时计算,不会执行括号内的表达式

int a = 10; sizeof(a++); // a++ 不会执行,a 仍然是 10

sizeof在处理数组和指针时有着本质的区别

重点!!!!!

sizeof是在编译时决定的,它只看变量的类型,不看变量里存了什么。

1. 对数组名使用sizeof

返回:整个数组占用的总字节数(数组长度 × 单个元素大小)

int arr[10]; // 10个int,每个4字节(32位系统) printf("%zu\n", sizeof(arr)); // 40 (10 * 4) ​ char str[20]; // 20个char,每个1字节 printf("%zu\n", sizeof(str)); // 20 ​ float nums[5]; // 5个float,每个4字节 printf("%zu\n", sizeof(nums)); // 20

2. 对指针使用sizeof

返回:指针变量本身的大小(固定值,与指向什么无关)

int *p1; char *p2; double *p3; int arr[10]; int *p4 = arr; ​ printf("%zu\n", sizeof(p1)); // 8 (64位系统) 或 4 (32位系统) printf("%zu\n", sizeof(p2)); // 8 (同上) printf("%zu\n", sizeof(p3)); // 8 (同上) printf("%zu\n", sizeof(p4)); // 8 (指针,不是数组!)

关键区别图:

int arr[10]; sizeof(arr) = 40 +----+----+----+----+----+----+----+----+----+----+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +----+----+----+----+----+----+----+----+----+----+ <------------------ 40 字节 --------------------> ​ int *p = arr; sizeof(p) = 8 +----------+ | 地址0x100| +----------+ <-- 8 字节 -->

解释:返回的是指针变量本身的大小,因为指针变量p它指向的是arr的数组元素的首地址,所以是八个字节

因为数组首元素地址的大小是固定的,在64位系统下。是8个字节,这和数组元素类型无关。因为地址本身就是一个指针,而指针的大小是由系统架构决定,而不由指向的数据类型决定。

地址 = 内存位置的编号 就像门牌号,不管房子里住的是人还是家具,门牌号本身都是同样大小

四、结构体的内存对齐

结构体的大小往往不是各成员大小的简单相加:

struct Example1 { char c; // 1字节 int i; // 4字节 }; // sizeof = 8(不是5) ​ struct Example2 { char c; // 1字节 char d; // 1字节 int i; // 4字节 }; // sizeof = 8(不是6) ​ struct Example3 { char c; // 1字节 short s; // 2字节 int i; // 4字节 }; // sizeof = 8(不是7) ​ // 内存布局示例(Example1): // +----+---+---+---+----+----+----+----+ // | c | 填充 | i | // +----+---+---+---+----+----+----+----+ // 0 1 2 3 4 5 6 7

对齐规则:

  • 每个成员按自己的对齐要求存放

  • 结构体大小是最大对齐数的整数倍

五、自增自减底层

*p++等价于*(p++)

由于后缀自增++的优先级高于解引用*,所以先执行p++,但p++返回的是p 的原值,然后对这个原值进行解引用。

表达式效果说明
*p++先取*p的值,然后p自增最常用
(*p)++先取*p的值,然后该值自增改变指向的内容
*++pp自增,再取*p的值先移动指针再取值
++*p先取*p的值,然后该值自增(*p)++

寄存器底层实现

int a = 5, b; b = ++a;
初始状态: a 地址: 0x1000, 值: 5 b 地址: 0x1004, 值: 未初始化 ​ 步骤1: 将 a 的值从内存加载到 CPU LOAD R1, [0x1000] ; R1 = 5 ​ 步骤2: CPU 计算加1 ADD R1, 1 ; R1 = 6 ​ 步骤3: 将新值写回 a 的内存地址 STORE [0x1000], R1 ; a = 6 ​ 步骤4: 将新值赋值给 b STORE [0x1004], R1 ; b = 6

b = ++a;底层是三步

  • 从内存读取a

  • 计算a+1并写回a

  • 将新值写入b

大白话说

++a:将a的值取出来,存入临时内存空间中。然后对a进行自增,再将新的值写入b,结束。(先自增,再赋值)

a++:将a的值取出来。存入临时空间中,将a的值先写入b,再对a进行自增,结束。(先赋值,再自增)


++*p是另一个常见的指针操作组合,它的含义和*p++完全不同。

++*p等价于++(*p)

由于前缀自增++和解引用*优先级相同,且结合性是从右向左,所以先计算*p,然后对结果进行自增。

六、引用与指针的区别

语法上

  1. 在语法上指针变量存储的是某个变量的地址或者实例的地址;引用存放的是变量或者实例的别名

  2. 程序为指针变量分配内存空间;不给引用分配内存空间

  3. 指针变量存在解引用一说,读取指针变量指向实例的内容;引用不存在解引用一说,访问实例的内容直接访问即可,引用就代表实例,引用的值就是实例的值

  4. 普通的指针变量可以存储其他实例的地址,也就是说指针变量可以改变指针指向的实例;而引用一旦代表了一个实例的别名,也就是说一旦初始化就不能修改,代表别的实例的别名

  5. 指针变量可以为空;引用不能为空,不能为空引用

  6. 作为形参时指针变量要验证他的全法性,即不能传入空指针;引用不需要验证,因为不存在空引用一说

  7. sizeof获取的是指针的大小(地址编号的大小);针对引用获取的是引用代表的实例的大小

  8. 指针存在层级,一级指针,二级指针。。。;引用不存在层级,二级引用。。。

  9. 自增自减针对指针变量是对指针指向的地址进行操作,移动到下一个实例的位置;引用进行自增自减是针对引用指向的实例进行算数自增自减操作

本质上

引用是指针的语法层概念,引用的本质就是指针

int& ra=a; int*const ra=&a;

引用是自身为常性的指针

七、函数在什么情况下能用引用的方式返回地址?

坚决不能将局部变量的地址返回

// ❌ 错误:返回局部变量的引用 int& badFunc() { int local = 10; return local; // 编译警告!local 在函数结束时销毁 } // 调用者得到一个悬空引用(野引用) ​ int& worseFunc() { int arr[10]; return arr[0]; // 同样错误 }

为什么错误?

  • 局部变量在栈上分配,函数结束时栈帧被回收

  • 返回的引用指向已释放的内存(未定义行为)

坚决不能将(已死亡)局部对象以引用的方式返回:解决方式就是加static

// ❌ 错误:返回临时对象的引用 int& badFunc2() { return 10; // 10 是临时量,立即销毁 } ​ string& badFunc3() { return string("hello"); // 临时 string 被销毁 }

静态变量的生命周期:

  • 程序启动时初始化(或首次调用时)

  • 程序结束时才销毁

  • 地址固定不变

可以安全返回引用的场景

  1. 静态局部变量(生命周期整个程序)

  2. 全局变量

  3. 类的成员变量(确保对象生命周期)

  4. 函数参数传入的引用(直接返回)

  5. 容器元素、数组元素(确保容器存在)

  6. *this(成员函数返回自身)

❌ 绝对不能返回引用的场景

  1. 局部变量(包括局部数组)

  2. 临时对象

  3. 函数内创建的局部对象

  4. 局部智能指针管理的对象(离开作用域就释放)

http://www.jsqmd.com/news/1022348/

相关文章:

  • MPC8315E DMA控制器:从原理到实战的嵌入式数据传输优化指南
  • 从响应式到预测式:基于Home Assistant构建智能家居个性化中枢
  • Python下划线的六种用法与工程实践指南
  • IntelliJ IDEA 集成 Codex 中转的六大道具级排错指南
  • 2026大连当地贵金属回收权威名录 TOP5 黄金金条铂金白银回收线下门店信息汇总 - 信誉隆金银铂奢回收
  • 一套键鼠控制多台电脑:Input Leap跨平台KVM终极指南
  • 2026宜春市黄金回收白银回收铂金回收彩金回收TOP5权威榜单:正规靠谱门店实地考察,高性价比首选+联系方式推荐 - 前途无量YY
  • 日期比较函数isBeforeOrSame的跨语言实现与避坑指南
  • 智能视觉SoC集成实战:从架构选型到产品落地的全链路解析
  • 程序员的心理学学习笔记 - 锚定效应
  • 2026海南旧金铂金白银回收高信赖门店 TOP 线下实体商家电话与门店地址一览 - 诚金汇钻回收公司
  • 2026白银建筑工程材料检测 CMA 机构哪家强?TOP 正规检测中心榜单 + 电话地址 - 中检检测集团
  • 智慧树刷课插件:3分钟实现网课学习效率翻倍终极指南
  • 大连想高价出足金?中山区这家老店不玩虚高报价引流套路 - 逸程
  • Python asyncio 入门:从事件循环到协程调度的底层原理
  • 2026益阳市黄金回收白银回收铂金回收彩金回收TOP5权威榜单:正规靠谱门店实地考察,高性价比首选+联系方式推荐 - 前途无量YY
  • GPT-5.5 Instant:响应压缩与记忆源驱动的即时智能范式
  • 3an推客是什么平台?资深运营深度解析合规电商增长工具
  • SSH 登录暴力破解日志检测脚本
  • 2026广元旧金铂金白银回收高信赖门店 TOP 线下实体商家电话与门店地址一览 - 诚金汇钻回收公司
  • 梯度提升算法原理与实战:从伪残差到弱树迭代
  • jcode:面向AI编码代理的Rust轻量级运行时框架
  • 终极Navicat无限试用重置:macOS用户告别14天限制的完整指南
  • 2026银川市黄金回收白银回收铂金回收彩金回收TOP5权威榜单:正规靠谱门店实地考察,高性价比首选+联系方式推荐 - 前途无量YY
  • 终极解放双手:Alas碧蓝航线全自动脚本完全指南 [特殊字符]
  • 四合一AI智能体:零基础搭建多模型协同工作台
  • 2026 免费投票小程序推荐|支持图文视频投票、不限人数免费导出数据不用付费 - 微信投票小程序
  • 5分钟解决Windows安卓驱动安装难题:一键自动化ADB Fastboot工具全攻略
  • 如何为Jellyfin构建完整中文番剧库?终极Bangumi插件完整指南
  • GPT-4o多模态能力实测与工程落地指南