对 const 的思考

用const 修饰的数值,一般是不可修改的,但在C语言中,可以通过变量的地址来修改其内容。

#include <stdio.h>

int main(int argc, char *argv[])
{
	const int i = 10;
	int *p = &i;	// 取i 的地址
	*p = 100;		// 修改地址里面的内容
	//i = 0;		// 报错!
	printf("*p = %d, i = %d\n", *p, i);

	return 0;
}

结果:

const 修饰的数值已经被修改了。

但是如果在C++中这么做,那么编译器会报错,说明C++的编译检查更加严格,那么按照通过变量地址来修改其变量的想法,进行修改。

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
	const int i = 10;
	int addr = (int)&i;
	int *p = (int*)addr;

	*p = 100; // 通过地址修改i 的值

	cout<<"*p = "<<*p<<", i = "<<i<<endl;

	return 0;
}

结果

i 的数值没有发生变化?!

调试:

在调试结果中,i 的数值已经是100了,打印的结果却还是原来的数值,通过反汇编代码可以看到,push 0AH。

也就是在打印的时候,并没有从i 的地址中重新去取数值,而是直接将i原始的结果push进去,所以结果没有变化。

是不是所有const修饰的数值,其使用和赋值都是通过原始的数值,而不是再从地址去数值?

简单测试代码:

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
	const int i = 10;
	const int j = 100;
	int k = 0;

	k = i;
	k = j;

	cout<<i<<", "<<j<<endl;

	return 0;
}

结果:

果然在C++中,从反汇编结果中知道,用const修饰的数值,在使用的时候,不会再从与原先的地址中取数值了,应该是用const修改的数值,被存放在寄存器中了,直接从寄存器中取值,而不会再从地址取值。

同样一段代码,如果用C语言编译,则会从原先的地址中取值。

总结:在反汇编代码中,加上 const 与没有加上 const 的反汇编代码是一样的,说明const 对实际代码并没有产生特别的影响,那么可知,const 只影响到编译器,也就是编译器会对const指向的数值进行检查,所以严格来说,const 修饰的不是一个常量,而是编译器的一种编译检查,应该说是变量的不可修改性。

对于const修饰的变量,在使用时:

在C语言中,会从原先的变量地址中,获取数值。(即可以通过变量的地址来修改const修饰的变量)

在C++语言中,不会从原先的变量地址中获取数值。(即即使通过变量的地址成功修改变量了,其变量在使用时,因为不会从地址中获取数值,所以还是原先的数值,说明C++的编译机制,更加保证了const修饰的变量的不可修改性)

时间: 2024-07-28 16:20:44

对 const 的思考的相关文章

涨知识---V

1.内存对齐 在解释内存对齐的作用前,先来看下内存对齐的规则: 1).  对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragma pack()指定的数,这个数据成员的自身长度) 的倍数. 2).  在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行.(默认是8,所以就是结构体中最大长度成员的字节数) #pragma pack(n) 表示设置为n

转:c/c++内存释放知识总结

转自:http://www.cnblogs.com/chuncn/archive/2011/04/12/2014273.html 基础知识:五大内存分区 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区.里面的变量通常是局部变量.函数参数等. 堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete.如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收.(new char;  delete char;

C中内存分配方式[转载]

在C 中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区. 一.简介: 1.栈,就是那些由编译器在需要的时候分配,在无需的时候自动清除的变量的存储区.里面的变量通常是局部变量.函数参数等. 2.堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程式去控制,一般一个new就要对应一个delete.假如程式员没有释放掉,那么在程式结束后,操作系统会自动回收. 3.自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,但是他是用free来

(c/c++内存管理)堆和栈的区别

摘要:内存管理向来是C/C++程序设计的一块雷区,大家都不怎么愿意去碰她,但是有时不得不碰它.虽然利用C++中的smart   pointer已经可以完全避免使用指针,但是对于对于指针的进一步了解,有助于我们编写出更有效率的代码,也有助于我们读懂以前编写的程序. 五大内存分区 在C++中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区. 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区.里面的变量通常是局部变量.函数参数等. 堆,就是那些由n

C++003基础

1.C++对C的扩展 1简单的C++程序 1.1求圆的周长和面积 数据描写叙述: 半径.周长,面积均用实型数表示 数据处理: 输入半径 r. 计算周长 = 2*π*r : 计算面积 = π* r2 . 输出半径,周长,面积: 方法1:用结构化方法编程,求圆的周长和面积 // count the girth and area of circle #include<iostream.h> using name std; void main () { double r, girth, area ;

内存中堆,栈的区别

原文链接:https://blog.csdn.net/tiger406/article/details/1192110 五大内存分区 看图: 在C++中,内存分成5个区,他们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区. 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区.里面的变量通常是局部变量.函数参数等.    堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete.如果程序员没有释放掉,那

数据结构(03)_顺序存储结构线性表

本节我们基于前面实现的数据结构类模板基础,继续完成基于顺序存储结构的线性表的实现,话不多说,继承关系图如下: 14.线性表的本质和操作 14.1.线性表的表现形式 零个多多个数据元素组成的集合 数据元素在位置上是有序排列的 数据元素的个数是有限的 数据元素的类型必须相同 14.2.线性表的抽象定义.性质 线性表是具有相同类型的n(>=)个数据元素的有限序列,(a0, a1, a2... an-1),其中ai是表项,n是表长度.性质: a0为线性表的第一个元素,只有一个后继 an-1为线性表的最后

指针系统学习4-字符串与指针

1.字符串与指针 (1) 用字符数组存放一个字符串,然后输出该字符串. 例题一:定义一个字符数组,对它初始化,然后输出该字符串. #include <stdio.h> void main() { char string[] = "I love Fishc.com!"; printf("%s\n", string); } (2) 用字符指针指向一个字符串 例题二:可以不定义字符数组,而定义一个字符指针.用字符指针指向字符串中的字符. #include &l

c++入门之类继承初步

继承是面向对象的一种很重要的特性,先来复习基类的基本知识: 先上一段代码: 1 # ifndef TABLE00_H 2 # define TABLE00_H 3 # include "string"; 4 using std::string; 5 class Player 6 { 7 private: 8 string first_name; 9 string last_name; 10 bool SEAT; 11 public: //注意,这里只是头文件,进行函数声明的地方 12