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

【C/C++】 从内存模型到访问权限:一文读懂常量指针与指针常量的本质区别

1. 指针基础与内存模型

在C/C++的世界里,指针就像是一把双刃剑——用得好能让你游刃有余,用不好则可能伤及自身。要理解常量指针和指针常量的区别,我们得先从内存模型这个底层视角说起。

想象你的电脑内存是一个超大型的储物柜,每个柜子都有唯一的编号(内存地址),里面可以存放各种物品(数据)。当我们声明一个变量时,比如int a = 10;,系统会分配一个柜子(假设编号0x1100)来存放这个整数。指针本质上就是记录这些柜子编号的便利贴,它自己也有个小柜子存放地址值。

在32位系统中,这个"便利贴"占4个字节(因为地址用32位表示);64位系统中则占8个字节。我经常用这个类比:指针就像酒店的前台登记簿,记录着每个客人(数据)的房间号,而解引用操作(*p)就是根据登记簿找到客人房间的过程。

int a = 10; // 数据存放在0x1100柜子 int *p = &a; // p的值是0x1100

2. const关键字的双重身份

const这个修饰符在C++中扮演着双重角色,就像瑞士军刀的不同功能:

  1. 常量修饰const int x = 5;表示x的值不可修改
  2. 指针修饰:当const遇到指针时,它的位置决定了限制对象

我有个简单的记忆口诀:"const靠谁近,谁就不可变"。比如:

  • const int *p:const修饰*p(内容不可变)
  • int * const p:const修饰p(指针本身不可变)

在实际项目中,我经常用const来防止意外修改。比如函数参数用const char*,就像给参数加了防篡改封条,既安全又表明设计意图。

3. 指针常量:锁定的导航仪

指针常量(int * const p)的特点是——指针本身的值(地址)不可变,但可以通过指针修改指向的内容。这就像你手机上的导航App被锁定了一个目的地,不能更改目的地地址,但可以修改目的地店铺的装修。

int a = 10, b = 20; int * const p = &a; // 初始化时必须赋值 *p = 30; // 合法:可以装修店铺 // p = &b; // 非法:不能更改导航目的地

在嵌入式开发中,我常用指针常量来访问固定的硬件寄存器地址。比如操作STM32的GPIO端口时,寄存器地址是芯片设计固定的,但需要读写寄存器值:

#define GPIOA ((volatile uint32_t * const)0x40020000) *GPIOA = 0xFFFF; // 可以修改寄存器值 // GPIOA = ...; // 禁止修改指针地址

4. 常量指针:防篡改的保险箱

常量指针(const int *p)则相反——可以改变指针指向的地址,但不能通过指针修改指向的内容。这就像银行保险箱的钥匙:你可以换不同的保险箱开,但不能修改保险箱里的物品。

int a = 10, b = 20; const int *p = &a; p = &b; // 合法:可以换保险箱 // *p = 30; // 非法:不能修改内容

在开发图像处理库时,我常用常量指针来传递图像数据,确保处理函数不会意外修改原始图像:

void processImage(const uint8_t *pixels, int width) { // 可以读取pixels数据 // 但不能通过pixels修改数据 }

5. 指向常量的指针常量:双重保险

当const同时出现在类型前和*后时(const int * const p),就形成了"双重锁定"——既不能修改指针指向的地址,也不能通过指针修改内容。这就像把珍贵文物锁进防弹玻璃展柜,既不能移动展柜,也不能触碰文物。

int a = 10; const int * const p = &a; // *p = 20; // 非法 // p = &b; // 非法

在开发安全敏感的系统时,比如支付模块,我会用这种双重保护来确保关键数据的安全。有一次我设计加密模块时,就用这种指针来保护密钥数据,既防止指针被篡改,也防止密钥被意外修改。

6. 从编译器视角看本质

理解这些区别的关键在于明白编译器如何解读const修饰。编译器会检查:

  1. 对指针变量本身的赋值(p = x)
  2. 通过指针的解引用操作(*p = x)

对于int * const p,编译器会阻止对p的赋值,但允许*p操作。而对于const int *p,则相反。我曾用Compiler Explorer工具查看过生成的汇编代码,发现编译器会对违规操作直接报错,根本不会生成对应指令。

7. 实战中的经典坑点

在多年开发中,我踩过不少关于指针的坑:

  1. 类型不匹配const int a = 10; int *p = &a;会导致编译错误,需要用const int *p
  2. 多级指针const int **ppint * const *pp的区别更复杂
  3. 函数返回:返回指向局部变量的指针是未定义行为

有个特别隐蔽的bug让我记忆犹新:在跨平台代码中,我误用了指针常量指向只读内存区域,在Windows上运行正常,但在嵌入式设备上硬故障。后来用const正确修饰后才解决问题。

8. 现代C++的替代方案

虽然理解这些概念很重要,但在现代C++中,我们有了更安全的替代方案:

  • 引用(const T&)比指针更安全
  • std::unique_ptrstd::shared_ptr管理生命周期
  • std::spangsl::span表示视图范围

不过在内核开发或嵌入式领域,原始指针依然无可替代。最近我在开发一个高频交易系统时,就不得不用指针常量来确保极致的性能。

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

相关文章:

  • 技术红线警示:从数模国赛查重机制看学术诚信的边界
  • 电动车实名挂牌管理系统源码(SSM+MySQL+JSP,含部署文档与答辩PPT)
  • DeepSeek V4 Flash:95%成本降低的AI Agent架构优化方案
  • 如何快速掌握DLSS Swapper:终极游戏性能优化秘籍
  • 【普中】基于51单片机电子钟万年历LCD显示与闹钟功能设计
  • 三维姿态的数学基石:从欧拉角到旋转矩阵的转换原理与实战陷阱
  • RagTag实战指南:从Contig到染色体水平组装的同源校正与支架构建
  • 10款常见的AI写小说工具实测:新手作者避坑指南(2026年最新)
  • 树莓派+YOLOv8n+Edge TPU实时目标检测实战指南
  • C/C++实现24位RGB颜色转换库:从HEX到HSV/HSL/CMYK的算法与工程实践
  • HarmonyOS APP实战-基于Image Kit的图像处理APP - 第13篇:打包发布与项目总结
  • 大脑决策机制颠覆认知,或为AI架构带来新启示
  • 从《讹诈》看权力博弈:技术时代下的心理操控与信息不对称
  • [安卓] 复刻 Apple Music 动态流体模糊背景:从色彩提取到平滑动画
  • Excel VBA 宏一键生成财务记账系统
  • 从《哈里森·伯杰龙》看技术乌托邦的悖论:当“平等”成为枷锁
  • 用交易数据做客户分群:从RFM到RFEAM的实战方法论
  • PowerDC IR Drop仿真:从原理到实战的避坑指南
  • I.MX6U SNVS-LP RTC驱动实战:从寄存器配置到低功耗时间管理
  • Matplotlib动态子图系统:基于SubplotSpec的可编程布局方案
  • L-BFGS-B:从理论到实践,解析大规模有界约束优化的高效算法
  • 多维聚合实战:用Pandas MultiIndex构建内存OLAP立方体
  • R语言实战:单因素方差分析全流程解析与多重比较可视化
  • 多目标追踪实战---从SORT到DeepSORT的演进与核心
  • 博客标题缺失:无法生成合规技术博文
  • Python诗歌分析:从平仄韵律到风格建模的NLP实践
  • 聚类算法全景解析:从K-means到谱聚类的核心思想与实战对比
  • 2026深度盘点10款写小说软件:写小说的都在用,高效体验ai生成小说!
  • M估计的迭代重加权最小二乘(IRLS)求解与C++实践
  • 【XJTUSE软件项目管理精讲】 第一章 从零到一:项目管理的核心概念与PMBOK第七版新视角