const到底是什么 二. 基本用法

本文深入探讨C++中const关键字的用法及规则,解析其在编译阶段的作用与运行时的表现,帮助读者理解const如何影响变量声明和指针操作。


const最基本的用法就是对一个变量的声明限制, 是和普通的变量声明放在一起的. 比如

const int myInteger = 5;

不过这种声明是在编译阶段就要有的一种约束, 这个关键字是为编译器所使用的. 注意这句话, const是应用于编译器检查的, 不是一个运行时的属性.
那么就可以回答前文的一个问题, 在内存中int和const int有什么区别呢? 可以说, 完全没有区别, 他们是一回事.

比如我写个例子.

const int myConst = 10;
int* pConst = const_cast<int*>(&myConst);
*pConst = 100;
printf("address(myConst) = %d, pConst = %d/n", &myConst, pConst);
printf("value(myConst) = %d, *pConst = %d/n", myConst, *pConst);

大家先不忙往下看, 在这段代码执行之前, 先预测一下执行的结果会是什么样呢?

首先, 两个地址是同一个内存. 其次, 输出的数据一个是10, 一个是100. 这下估计很多朋友要大吃一惊了, 为什么同样的一个内存里居然会保存两个数据... 呵呵, 这就是const所谓的编译规则, 而不是运行时规则. 大家理解一下哦.


在编译的时候, 编译器已经对被声明为const的变量在引用处已经进行了优化. 因为这对编译器来说很合理啊, 反正你的这个变量是不可修改的, 那么为了提高效率, 我在运行时就把它的值用起来, 何必要等到运行时再取呢? 于是第二个printf语句被编译器作了个优化, 实际上是形如如下的伪码了.
printf("value(myConst)=%d, *pConst=%d/n"), 10, *pConst);

这是一个比较隐晦的问题, 但是我很乐意把它拿到开始来与大家分享, 因为这是const用法的指导原责.

 

好, 现在我们回到
const int myInteger = 5;
接着往下推理一下规则吧. 既然是一个常量是不可以修改的, 那么其他的赋值语句, 就是不可接受的. 这时再来一个myInteger = 10;就会被编译器视为一个错误. 好了, 这样一个声明的格式被接受, 一个赋值的语句被报错, 我们又可以生成一个新的规则, 即const所声明的东西, 必须是在初始化之前时有值.

那么, 请大家再看下面的句子.
int a = 10;
int b = 5;
const int* pInt = &a;
pInt = &b;
这段代码却是没有问题的, 会不会有人又很奇怪呢? 这不是和刚才说的"const声明的东西必须是在初始化之前时有值". 矛盾吗? 不矛盾, 请注意看清楚前面是写作const int myInteger = 5; const修饰的目标是int, 表示说这是一个int型的常量. 而后边的写法很容易让人混淆, const int* pInt; 那个*号是服务于pInt, 而不是服务于int的. 这个声明的意思是, 声明了一个指向常量的指针. 再换句话说, 不允许用户通过这个指针改变任何一个变量的值... 对于这个指针指向哪里可没有任何约束的... 哈哈哈. 于是我们反推出一个结论,
int* p, q; 是什么意思? 它声明了一个int变量q, 一个int型指针p. 那个*号是和int无关的. 那么大家在声明的时候, 为了规范和减少别人误解的可能(后期维护人员的水平可不一定比你高), 还是请写成这个样子: int *p, q; 这个*号修饰谁, 我们就把它放在什么地方...

如果你想用const约束一个指针, 那么请写作如下
const int a = 10;
const int b = 5;
int* const pInt = &a;     //通过
pInt = &b;         //失败
这就看出, const直接修饰的目标是不可改的. 现在const已经在修饰一个指针类型了, 所以给它重新赋一个地址, 就是不可接受的. 同时, 也看出C++的一个词法上的不足之处. 它在声明指针类型时, 推荐*与变量名为一个整体, 以区分另一个指针变量. 但是在声明const时, 却又使用类型*的格式实现. 这是一个容易混淆的地方. 须注意.


那么我再极端一点作下面的操作,
int a = 10;
int* const pA = &a; 会发生什么呢?
希望您不要被刚才的一大端const给弄糊涂. 这段代码是错的. 因为赋值号两端的数据类型完全不匹配. 左边的类型是int* const, 右边的类型是int*

好了, 说到底, 我们现在可以得出下面的几个结论了:
1. const是编译时的声明
2. const只修饰它直接服务的目标, 并对针对它的操作进行限制
3. const也是类型声明的一部分.
4. const对声明的风格也会有适当的要求.

`const` 是 C 语言中的一个关键字,用于声明“不可修改的变量”或“只读对象”。它告诉编译器某个值在初始化后不能被修改,从而提高程序的安全性和可读性。 ### 1. 基本用法:定义常量 ```c const int MAX = 100; ``` 这表示 `MAX` 是一个整型常量,其值不能被修改。尝试修改会引发编译错误: ```c MAX = 200; // 错误:不能修改 const 变量 ``` 等价于使用 `#define MAX 100`,但 `const` 具有类型检查,更安全。 --- ### 2. 指针与 const 的结合(重点) `const` 在指针中的使用较为复杂,取决于它修饰的是指针本身还是指针指向的数据。 #### (1) 指向常量的指针(数据不能改,指针可以改) ```c const int *p; // 或 int const *p; ``` - 指向的数据是常量,不能通过 p 修改。 - 指针 p 本身可以指向其他地址。 ```c int a = 10, b = 20; const int *p = &a; *p = 100; // 错误:不能修改 *p p = &b; // 正确:可以改变指针指向 ``` #### (2) 常指针(指针不能改,数据可以改) ```c int *const p = &a; ``` - 指针 p 一旦初始化就不能再指向别的地址。 - 但可以通过 p 修改所指向的数据。 ```c *p = 100; // 正确:可以修改 *p p = &b; // 错误:不能修改指针本身 ``` #### (3) 指向常量的常指针(都不能改) ```c const int *const p = &a; ``` - 既不能修改指针指向,也不能通过 p 修改数据。 ```c *p = 100; // 错误 p = &b; // 错误 ``` --- ### 3. 函数参数中的 const 用于防止函数修改传入的参数,尤其是数组或指针: ```c void print(const int arr[], int n) { for (int i = 0; i < n; i++) { printf("%d ", arr[i]); // arr[i] = 0; // 错误:不能修改 } } ``` 这保证了函数不会意外修改原数组内容。 --- ### 4. const 与宏定义的区别 | 特性 | `const` | `#define` | |------------------|----------------------------------|-------------------------------| | 类型检查 | 有 | 无(纯文本替换) | | 调试信息 | 支持(变量名可见) | 不支持 | | 存储空间 | 可能分配内存(取决于优化) | 不分配 | | 作用域 | 遵循变量作用域 | 全局,直到 #undef | 推荐优先使用 `const` 替代简单的宏常量。 --- ### 示例代码总结: ```c #include <stdio.h> int main() { const int MAX = 100; int a = 10, b = 20; const int *p = &a; // 指向常量的指针 int *const q = &a; // 常指针 const int *const r = &a; // 指向常量的常指针 // *p = 100; // 错误 p = &b; // 正确 *q = 100; // 正确 // q = &b; // 错误 // *r = 100; // 错误 // r = &b; // 错误 printf("MAX = %d\n", MAX); return 0; } ``` --- ### 注意事项: - `const` 变量必须在定义时初始化(除了 extern 情况)。 - 编译器可能将 `const` 全局变量放入只读段,试图修改会导致运行时错误(如段错误)。 - 使用指针强制修改 `const` 变量(如 `(int*)&MAX`)属于未定义行为(UB),应避免。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值