const在C与C++中的区别
在C中,const不是常量,只能说是一个不能改变的变量(注意是变量),C编译器不能把const看成看成一个编译期间的常量,因为他在内存中有分配,C编译器不知道他在编译期间的值。所以不能作为数组定义时的下标,因为它必须为常量。
在C中,const int a;是可以的,因为这只是声明一个变量,告诉编译器,我这里是声明,指明在别的地方有内存分配。但在C++中这样写是不正确的,C++中const默认是内部链接,C中默认是外部链接,为了起到和c语言一样的效果,C++需要将const修饰为extern,因为extern优先级高于const,所以变量会被变为extern外部链接,起到和C语言一样的效果。[ (1) 内连接:编译器只对正被编译的文件创建存储空间,别的文件可以使用相同的表示符或全局变量.C/C++中内连接使用static关键字指定.(2) 外连接:所有被编译过的文件创建一片单独存储空间.一旦空间被创建,连接器必须解决对这片存储空间的引用.全局变量和函数使用外部连接.通过extern关键字声明,可以从其他文件访问相应的变量和函数. ] 通俗的讲:在c++ 中const 对象默认为文件的局部变量。与其他变量不同,除非特别说明,在全局作用域声明的 const 变量是定义该对象的文件的局部变量。此变量只存在于那个文件中,不能被其他文件访问。通过指定 const 变更为 extern,就可以在整个程序中访问 const 对象。
C++中是否为const分配内存空间要看具体情况,如果被声明为extern或者取const变量地址,就需要为const变量分配空间。
当在自己的文件中使用const的时候,C++不会为const常量分配空间,因为这是一种优化措施,没有必要浪费空间去存储一个常量,此时const int a=5 就相当于#define a 5,当在其他文件使用的时,需要分配内存,同样在程序内部引用的时候,也需要分配内存,因为这两者都是采用寻址的技术去使用的,不分配内存就没有地址。C++中定义常量的时候不再采用define,因为define只做简单的宏替换,并不提供类型检查。
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;
return ;
} /*运行结果:
-----------
010FF958
010FF958
2
30
-----------
*/
通过 int*p = (int*)(&a);这种方法,可以直接修改const常量对应的内存空间中的值,但修改不会影响到常量本身的值,因为用到a的时候,编译器根本不会去进行内存空间的读取。这就是C++的常量折叠constant folding,即将const常量放在符号表中,而并不给其分配内存。编译器直接进行替换优化。除非需要用到a的存储空间的时候,编译器迫不得已才会分配一个空间给a,但之后a的值仍旧从符号表中读取,不管a的存储空间中的值如何变化,都不会对常量a产生影响。
但是在C语言中却不是这样,C没有constant folding的概念,用const定义一个常量的时候,编译器会直接开辟一个内存空间存放该常量。不会进行优化。同样的例子在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 ;
} /*运行结果
------------
61fe14
61fe14
30
30
------------*/
C中,一个被const定义为常量的值,却能被修改,而且编译器不报任何错误 。进一步深入可发现,对于以上两个例子来说,a都是定义在某个函数之内的(比如main()函数),不管是C还是C++,本质上都只是将其当成一个普通的局部变量来对待,都只是在栈上分配空间。所以const根本就不能起到阻止修改其内存空间的作用,一个合法的强制类型转换就可以轻松搞定。C++比C好的地方就在于使用了constant folding的机制,使得常量的值跟对应的内存空间无关,从而保护了该常量值。
const int a = ;
int arr[a];
但C会报错: error: variably modified 'arr' at file scope, 原因在于GCC认为a只是一个普通的全局变量,而变量是不能用来指定数组的长度的,这是针对全局数组而言。但如果是局部的数组的话,就算是int a = 3; int arr[a];这种都是可以的,若在C和C++中如果我们仍然用int *p = (int*)(&a);这种方法来修改它内存中的值,编译时不会报错,但是运行时会报错误,因为a是放在只读的全局数据区中,修改该区中的数据会引发段错误。
const在C与C++中的区别的更多相关文章
- 面试问题5:const 与 define 宏定义之间的区别
问题描述:const 与 define 宏定义之间的区别 (1) 编译器处理方式不同 define宏是在预处理阶段展开: const常量是编译运行阶段使用: (2) 类型和安全检查不同 ...
- 总结const、readonly、static三者的区别【收藏、转载】20190614
总结const.readonly.static三者的区别 const:静态常量,也称编译时常量(compile-time constants),属于类型级,通过类名直接访问,被所有对象共享! a.叫编 ...
- js中== 和===中的区别
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- continue语句在for语句和while语句中的区别
while语句的形式: while( expression ) statement for语句的形式: for( expression1; expression2;expression3 ) // ...
- Objective-C声明在头文件和实现文件中的区别
Objective-C声明在头文件和实现文件中的区别 转自codecloud(有整理) 调试程序的时候,突然想到这个问题,百度一下发现有不少这方面的问答,粗略总结一下: 属性写在.h文件中和在.m文件 ...
- 在oracle中where 子句和having子句中的区别
在oracle中where 子句和having子句中的区别 1.where 不能放在GROUP BY 后面 2.HAVING 是跟GROUP BY 连在一起用的,放在GROUP BY 后面,此时的作用 ...
- import,reload,__import__在python中的区别
import,reload,__import__在python中的区别 http://blog.csdn.net/five3/article/details/7762870 import作用:导入/引 ...
- 代码演示C#中string和StingBuilder内存中的区别
关于 string和StringBuilder的区别参考MSDN.本文用程序演示它们在内存中的区别,及其因此其行为不同. //Demo string memory model namespace C ...
- Lib作为“静态库”与“动态库”中的区别
Lib作为“静态库”与“动态库”中的区别 0. 前言: 什么是静态连接库: 静态库在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中.因此对应的链接方式称为静态链接. 为什么 ...
随机推荐
- phpstorm安装bootstrap插件
一个插件可以很好的让我们工作节约时间 Bootstrap,来自 Twitter,是目前最受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的,它简洁灵活,使得 We ...
- laravle中orm简单的增删改查
友情提示请在有laravel基础的情况下观看文章 1.数据库信息(user表) CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, ...
- react-路由和Ant design
路由的使用 react-router import React from 'react' // 如果要使用 路由模块,第一步,运行 yarn add react-router-dom // 第二步,导 ...
- Python的字典、列表合并
字典合并: 在日常工作中需要对字典进行合并操作,下面提供几个操作方法 1.使用dict(a,**b) 例: >>> a={'a':1,'b':2} >>> b={' ...
- win10驱动签名禁用与启动
禁用:https://jingyan.baidu.com/article/624e74594dbc8d34e8ba5aa6.html?qq-pf-to=pcqq.c2c 启用或恢复:https://z ...
- 在Unity5中使用C#脚本实现UI的下滑、变色、渐隐渐现效果
一.首先,我们先创建一个Text 依次选择Component→UI→Text创建一个Text,创建完成后如下: 二.创建完成后,在Project面板点击Create→C# Script,本例命名 ...
- android获取系统信息
连接手机,adb shell 进入 Android Shell 模式,输入 getprop 获取系统属性值 通过上面方法拿到属性名,然后通过下面方法获取到系统的属性值 /** * 获取build.pr ...
- 风变编程笔记(二)-Python爬虫精进
第0关 认识爬虫 1. 浏览器的工作原理首先,我们在浏览器输入网址(也可以叫URL),然后浏览器向服务器传达了我们想访问某个网页的需求,这个过程就叫做[请求]紧接着,服务器把你想要的网站数据发送给浏 ...
- 深度优先搜索 DFS(Depath First Search, DFS)
深度优先搜索是一种枚举所有完整路径以遍历所有情况的搜索方法.(不撞南墙不回头) DFS一般用递归来实现,其伪代码思路过程一般如下: void DFS(必要的参数){ if (符和遍历到一条完整路 ...
- 题解【AcWing176】装满的油箱
题面 一开始拿到这个问题并不好做,于是考虑拆点. 考虑将一个点拆成 \(c+1\) 个,每个点表示(编号,剩余油量). 然后 \(\text{Dijkstra}\) 最短路即可. 每次跑 \(\tex ...