const分别在C和C++语言里的含义和实现机制

const的含义

       简单地说:const在c语言中表示只读的变量,而在c++语言中表示常量.

C语言

const是constant的缩写,是恒定不变的意思,也翻译为常量,但是很多人都认为被const修饰的值都是常量,其实这是不精确的.因为,精确来说应该是只读的变量,其值在编译的时候不能被使用,因为编译器在编译的时候不知道其存储的内容.或许当初这个关键字应该被替换为readonly.

C语言中const定义的变量只是给出了对应的内存地址,而不是像#define一样给出的是立即数,所以,const定义的只读变量在程序运行过程中只有一个备份(因为它是全局的只读变量,存放在静态区),而#define定义的宏变量在内存中有若干个备份.

c++语言:

const是C++中常用的类型修饰符,常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的.

C++引入const的初始目的是为了取代预编译指令,消除他的缺点,同时继承它的优点.<缺点:只是简单值和代码的替代,缺乏类型的检测机制,安全性不好;优点有三:1.避免意义模糊的数字出现,清晰程序语义2.方便参数的调整和修改,3.提高程序执行效率,因为不需要为常量分配空间>

问题出来了:为什么const能取代预定义语句?

1.   首先,以const修饰的变量和对象具有不可变性,这是它能取代预定义语句的基础.

2.   第二,很明显,它同样能避免意义模糊的数字定义,也可以方便地进行参数的调整与修改.

3.   第三,c++编译器通常不为普通const常量(普通是指内置类型,不包括结构体等类型)分配存储空间,只是把它们保存在符号表中(注意:c语言中则会为const变量分配存储空间),这使得它们成为了编译期间的常量,没有了存储和读内存的操作,使得它的效率非常高,同时,也是它能取代预定义语句的重要基础.

4.   最后,const定义也能像普通的变量定义一样,它会由编译器对它进行类型的安全检查,消除了预定义语句带来的安全隐患.

我们使用一张表来总结const的作用:


No.


作用


说明


参考代码


1


可以定义const常量


 


const int Max = 100;


2


便于进行类型检查


const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误


void f(const int i) { .........}
      //对传入的参数进行类型检查,不匹配进行提示


3


可以保护被修饰的东西


防止意外的修改,增强程序的健壮性。


void f(const int i) { i=10;//error! }
      //如果在函数体内修改了i,编译器就会报错


4


可以很方便地进行参数的调整和修改


同宏定义一样,可以做到不变则已,一变都变


 


5


为函数重载提供了一个参考


 


class A
{
           ......
  void f(int i)       {......} //一个函数
  void f(int i) const {......} //上一个函数的重载
           ......
};


6


可以节省空间,避免不必要的内存分配


const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝


#define PI 3.14159         //常量宏
const doulbe  Pi=3.14159;  //此时并未将Pi放入ROM中
              ......
double i=Pi;   //此时为Pi分配内存,以后不再分配!
double I=PI;  //编译期间进行宏替换,分配内存
double j=Pi;  //没有内存分配
double J=PI;  //再进行宏替换,又一次分配内存!


7


提高了效率


编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高


 

const的实现机制

const究竟是如何实现的呢?对于声明为const的内置类型,例如int,short,long等等,编译器会如何实现const的本意?那么对于非内置类型是否也是与内置数据类型一样处理呢,例如对于结构体类型则会怎样处理呢?下面通过几个小例子来说明这些问题: 
C语言const示例

const int i=10; 
int *p=(int *)(&i); 
*p=20; 
printf("i=%d *p=%d \n",i,*p);

猜一猜输出结果是什么? i=20 *p=20 
C++语言const示例1:

const int i=10; 
int *p=const_cast<int *>(&i); 
*p=20;

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

输出结果是 i=10 *p=20 
C++语言const示例2:

struct test{ 
int j; 
char tmp; 
test() 

j=30; 
tmp=‘a‘; 

}; 
int main(int argc, char* argv[]) 

const struct test t1; 
int *q=(int *)(&t1.j); 
*q=40; 
cout<<"j="<<t1.j<<"*q="<<*q<<endl; 
return 0; 
}

输出结果是 j=40 *q=40

示例结果分析 
看到上面三组输出结果,我们可以分析两个问题:

问题1:C语言和C++语言中的const究竟表示什么?

问题2:const的实现机制究竟是怎样的?

问题1,对于const int类型的变量i,C语言中通过指针p修改了值后,i变成了20;而在C++中,通过指针p修改了值后,i仍然是10。 
问题2,C++语言中 const struct test的元素j通过指针q被改变了,为何const int 与 const struct test的反应机制不同?

针对问题1,我们知道C语言中const表示只读的变量,既然把const看成是变量,那么其在内存中就会有存储他的空间,并且可以通过指针间接的改变该内存空间的值,当通过指针p改变该内存中的值后,再获取i的值的时候,会访问该空间,得到的是被改变后的值。而C++把const看做常量,编译器会使用常数直接替换掉对i的引用,例如cout<<i; 会理解成cout<<10; 并不会去访问i的内存地址去取数据,这里有点像是C语言里的宏#define i 10。因此C++里i会输出10,而*p会输出20.

针对问题2,C++语言中只是对于内置数据类型做常数替换,而对于像结构体这样的非内置数据类型则不会。因为结构体类型不是内置数据类型,编译器不知道如何直接替换,因此必须要访问内存去取数据,而访问内存去取数据必然会取到被指针q改变后的值,因此会造成与C++中const int类型完全不一样的处理模式。

参考文章:http://blog.csdn.net/chenhuajie123/article/details/9221149

时间: 2024-12-28 14:53:07

const分别在C和C++语言里的含义和实现机制的相关文章

[原创]C语言里为何会有“2+2=5”的结果

原文链接:C语言里为何会有“2+2=5”的结果 写这篇原创文章是因为看到了极客中的一篇文章<有趣各种编程语言实现2+2=5>,其中C语言是这样实现的: 1 int main() { 2 char __func_version__[] = “5″; // For source control 3 char b[]=”2″, a=2; 4 printf(“%d + %s = %s\n”, a, b, a+b); 5 return 0; 6 } 有些童鞋可能会说,这不是偷换概念吗,拿字符串和int相

C语言里全局变量管理

C语言里信息封装比較弱,仅仅有静态变量的文件作用域. 假设不加约束.非常easy造成全局变量满天飞. 假设定义一个全局结构体.把全局变量都放到这个GlobleVariate里,应该好管一些,至少比裸奔文雅一点. 更进一步,每一个模块定义自己的结构体.把模块公共变量放到结构体里.这样把GlobleVariate拆成多个小结构体,会更文雅一些. 大概的伪代码是以下这个样子. struct GlobleVariate { struct ModuleVariate1: struct ModuleVari

c语言里NULL的理解

NULL一看名字就知道为空,什么为空呢,而且全是大写.是不是意味着是个宏定义呢?如果想到这里,我相信你离真理不远了. 有些人为什么犯错?因为只看到了NULL这四个字母而已,没有看到事物的本质,老师在课堂上也只是说空指针,空字符串..这样只会陷入无止境的误区.如果我这样定义: #define NULL 0 你是不是又该纠结了呢? 正确的做法是把它当作一个宏,不管如何变化,来展开看看就知道了. 在C语言的头文件stddef.h中,NULL的定义如下: #define NULL #define __c

C语言里为何会有“2+2=5”的结果

写这篇原创文章是因为看到了极客中的一篇文章<有趣各种编程语言实现2+2=5>,其中C语言是这样实现的: int main() { char __func_version__[] = "5″; // For source control char b[]="2″, a=2; printf("%d + %s = %s\n", a, b, a+b); return 0; } 有些童鞋可能会说,这不是偷换概念吗,拿字符串和int相加,是滴,但在这里请这些童鞋暂且

嵌入式C语言里的土豪们之除法与移位

土豪这个词用在接下来要出场的C语言再合适不过了.他们在嵌入式C语言里占尽了奢华,但是毕竟我们更需要一个节约型的微生态环境.在这里简单给大家分析一下嵌入式C语言编程时用到的除法与移位. 本文引用地址:http://www.eepw.com.cn/article/182359.htm 除法土豪 除法在嵌入式微处理器里可算是一个消耗大户,复杂的实现方式不仅占用了大师宝贵的计算时间而且精度有限情况下占用了大片的RAM.因此,常常在各类文章里看到,编程人员应该使用右移运算来代替除法.这个右移方法没有问题,

C++里面的const和c语言里面的const

众所周知:在C语言里面用const:是可以修改的: //C语言里面可以通过指针修改 int main() { //可以这么说在C语言中a是一个只读的常量.按照理论我们不好修改// const int a=10; printf("%x",&a);//c语言里面的 常量a是可以去地址的. int *p=null; p=(int *)&a; //但是可以通过地址修改 *p=11; printf("修改之后%d",a); } 这里面的a是可以修改的: 但是看

C语言里字符串的解析

原文网摘:http://www.cnblogs.com/yi-meng/p/3620244.html#undefined 根据给定的字符串,按照一定规则解析字符串,卡住好几次,这次做个笔记,以供参考 函数名称:   strtok 函数原型:   char *strtok(char *s1, const char *s2) 函数功能:   分解s1字符串为用特定分隔符分隔的多个字符串(一般用于将英文句分解为单词) 函数返回:   字符串s1中首次出现s2中的字符前的子字符串指针 参数说明:   s

如何在C语言里实现“面向对象编程”

有人认为面向对象是C++/Java这种高级语言的专利,实际不是这样,面向对象作为一种设计方法,是不限制语言的.只能说,用C++/Java这种语法来实现面向对象会更容易.更自然一些. 在本节中,就展示如何在C语言中实现面向对象编程,这是一件吃力的工作.写这些的目的有两个: ① 更好的掌握C++中的class的概念.学习了本章,就知道C程序员的无耐,就知道为什么要发明一个class的概念.为什么要有成员函数等等. ② 为C程序员提供一个参考设计.由在存在某些场合,只允许用C语言来编程,不允许用C++

理解Python语言里的异常(Exception)

Exception is as a sort of structured "super go to".异常是一种结构化的"超级goto". 作为一个数十年如一日地钟爱C语言的程序员(因为C程序员需要记忆的关键字很少,而且可以很惬意地玩内存),对于高级语言如Python里的异常(Exception)一直不甚理解,尤其是其实现机理.但读了<Learning Python>一书中上面这句话(尤其是goto关键字)后,忽然豁然开朗. 如果用C语言编写一个鲁棒性良