c和c++关于const的一些区别
以下参考了网上的一些资料并通过程序验证。
注意,以下情况都是用gcc和g++编译器得到的结果,用vs编译器又会有所不同。
以下说下c和c++中const定义的常量的一些区别:
c++中用const定义了一个常量后,不会分配一个空间给它,而是将其写入符号表(symbol table),这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。但是const定义的常量本质上也是一个变量,是变量就会有地址,那么什么时候会分配内存?看看下面的代码:
int main(){
const int a = ;
int* p = (int*)(&a);
*p = ;
cout<<&a<<endl;
cout<<p<<endl;
cout<<a<<endl;
cout<<*p<<endl;
}
结果:

我们看到,通过 int*p = (int*)(&a);这种方法,可以直接修改const常量对应的内存空间中的值,但是这种修改不会影响到常量本身的值,因为用到a的时候,编译器根本不会去进行内存空间的读取。这就是c++的常量折叠(constant folding),即将const常量放在符号表中,而并不给其分配内存。编译器直接进行替换优化。除非需要用到a的存储空间的时候,编译器迫不得已才会分配一个空间给a,但之后a的值仍旧从符号表中读取,不管a的存储空间中的值如何变化,都不会对常量a产生影响。
但是在c中却不是这样.c没有constant folding的概念,用constant定义一个常量的时候,编译器会直接开辟一个内存空间存放该常量。不会进行优化。同样的例子在c下面会产生不同的结果:
int main()
{
const int a = ;
int* p = (int*)(&a);
*p = ;
printf("%x\n",&a);
printf("%x\n",p);
printf("%i\n",a);
printf("%i\n",*p);
return ;
}
结果:

我们看到,在c里面,一个被const定义为常量的值,堂而皇之地被修改了,而且编译器没有报任何错误 !
如果我们进一步深入可以发现,对于以上两个例子来说,a都是定义在某个函数之内的(比如main()函数),不管是c还是c++,本质上都只是将其当成一个普通的局部变量来对待,都只是在栈上分配空间。所以const根本就不能起到阻止修改其内存空间的作用,一个合法的强制类型转换就可以轻松搞定。c++比c好的地方就在于使用了constant folding的机制,使得常量的值跟对应的内存空间无关,从而保护了该常量值。
以上的例子是针对局部的const常量而言,对全局的const变量,c++仍旧采用constant folding策略,故以下代码是行得通的:
//global variable
const int a = ;
int arr[a];
但是c会报错: error: variably modified 'arr' at file scope, 原因在于gcc认为a只是一个普通的全局变量,而变量是不能用来指定数组的长度的。当然,这是针对全局数组而言,如果是局部的数组的话,就算是int a = 3; int arr[a];这种都是可以的,因为c里面还有一种叫变长数组的东西(我晕~,貌似因为两者的实现机制不一样,这个要再看看)
另外,对于a,在c和c++中如果我们仍然用int *p = (int*)(&a);这种方法来修改它内存中的值,编译时不会报错,但是运行时会报段错误,因为a是放在只读的全局数据区中,修改该区中的数据会引发段错误。
在vs编译器下:
1.不支持变长数组,一个变量除非被声明为const,否则不能用来声明数组的长度。
2.const变量,不管是全局的还是局部,都是放在只读数据区,所以无法用前面的方法来修改内存空间里面的值,编译时就会报错。
c和c++关于const的一些区别的更多相关文章
- const int *p与int *const p的区别(转:csdn,suer0101)
本文只是一篇学习笔记,是看了<彻底搞定C指针>中的相关篇幅后的一点总结,仅此而已! 一.先搞清const int *p与int const *p的区别 它们的区别就是:没有区别!! 无论谁 ...
- #define和const的简单区别
面试常问:宏#define和const有什么区别? 1.编译器处理方式 define宏是在预处理阶段展开 const常量是在编译阶段使用 2.类型和安全检查不同 define宏没有类型,不做安全检查, ...
- let、var、const声明的区别
前言 看了方应杭老师的一篇解释let的文章,对JavaScript中的声明有了深刻的理解,这里也就有了总结一下JavaScript中各种声明之间区别的这篇文章. JavaScript中变量声明机制 首 ...
- js中const,var,let区别(转载)
js中const,var,let区别 来源:https://www.cnblogs.com/zzsdream/p/6372729.html 今天第一次遇到const定义的变量,查阅了相关资料整理了这篇 ...
- #define宏常量和const常量的区别
C++ 语言可以用const 来定义常量,也可以用#define 来定义常量.但是前者比后者有更多的优点:(1) const 常量有数据类型,而宏常量没有数据类型.编译器可以对前者进行类型安全检查.而 ...
- const 和 #define区别_fenglovel_新浪博客
const 和 #define区别 (2012-12-11 14:14:07) 转载▼ 标签: 杂谈 (1) 编译器处理方式不同 define宏是在预处理阶段展开. const常量是编译运行阶段使 ...
- void fun() const{}; const void fun(){}; 和void const fun(){}; 的区别?
void fun() const{}; const void fun(){}; 和void const fun(){}; 的区别? const void fun(){};和void const fun ...
- const,var,let区别(转载)
1.const定义的变量不可以修改,而且必须初始化. const b = 2;//正确 // const b;//错误,必须初始化 console.log('函数外const定义b:' + b);// ...
- C++(十九) — const 和 #define 区别
1.const (1)C++对 const 常量的处理过程:当编译器碰到 常量声明 时,在符号表中放入常量,编译时发现使用常量,则直接以符号表中的值替换. (2)如果,编译中发现,对 const 使 ...
- const,var,let 区别
js中const,var,let区别 1.const定义的变量不可以修改,而且必须初始化. 声明的是常量 1 const b = 2;//正确 2 // const b;//错误,必须初始化 3 co ...
随机推荐
- 【原】《Git教程》学习笔记
[TOC] 1 创建版本库 1.1 初始化 初始化一个Git仓库,使用 git init 命令. 添加文件到Git仓库,分两步: 第一步,使用命令git add <file> ,注意,可反 ...
- Atitit 网络爬虫与数据采集器的原理与实践attilax著 v2
Atitit 网络爬虫与数据采集器的原理与实践attilax著 v2 1. 数据采集1 1.1. http lib1 1.2. HTML Parsers,1 1.3. 第8章 web爬取199 1 2 ...
- atitit.动态加载数据库配置in orm hibernate mybatis
atitit.动态加载数据库配置in orm 1. 动态加载数据库配置的优点::: 1 1.1. 组合多个配置文件... 1 1.2. 连接多个数据库 1 2. 基本的流程:::getCfg内存对象, ...
- 适合于小团队产品迭代的APP测试流程
一.测试周期 测试周期一般为2~3天,根据项目情况以及版本质量可适当缩短或延长测试时间.正式测试前先向主管或产品经理确认项目排期. 二.测试资源 测试任务开始前,检查各项测试资源. 产品功能需求文档. ...
- Leetcode 205 Isomorphic Strings 字符串处理
判断两个字符串是否同构 hs,ht就是每个字符出现的顺序 "egg" 与"add"的数字都是122 "foo"是122, 而"ba ...
- Android onTouch事件传递机制
Android onTouch事件介绍: Android的触摸事件:onClick, onScroll, onFling等等,都是由许多个Touch组成的.其中Touch的第一个状态肯定是ACTION ...
- (一)MVC5干货篇,目录和路由
MVC目录结构概述 文件夹或文件 描述 备注 /App_Data 此文件夹用于存放私有数据,如XML,或者SQL Server Express\SQLite的数据库文件,或其他基于文件的存储库 IIS ...
- JQ中mouseover和mouseenter的区别
我最近也在学习JQuery,所以最近对JQ中的一些小问题进行总结,方便学习. 在对于刚开始学习JQ的初学者来说,mouseover事件和mouseenter事件总是傻傻分不清楚,毕竟刚开始学习的时候, ...
- 开发ERP软件应该遵守的22条规则
总结一下做管理软件,有哪些项是经过检验的条款,必须遵守的. 界面篇 1 要保存用户的偏号(profile/favourite). ASP.NET 2.0引入此功能,当用户修改默认的控件的属性时,框架 ...
- ClamAV安装使用及API例子
ClamAV是一款由Sourcefire组织开发的开源杀毒引擎,Sourcefire同时也是Snort入侵检测引擎的所有者.ClamAV提供了一种更为快速灵活的框架用以检测恶意代码和软件产品.可以作为 ...