今天偶然想起const这一关键字,再加之以前几种const修饰指针方式让我印象深刻(混淆不清),重新回顾了一下,自己对这个关键词也又有了更加深刻的理解,所以总结一下。

一、const的定义

  const修饰的数据类型是指常类型,常类型的变量或对象的值是不能被更新的。

二、const的由来

  最初的目的是为了取代预编译指令define,继承define的优点并且摈弃它的缺点。

举两个例子:

  1.从内存角度

 #define   MAX_D   10
const int MAX_C = ; //此时保存在符号表,未分配内存 int main(void)
{
int num_d = MAX_D; //预编译过后这句话就是int num_d = 10;(分配内存)
int num_c = MAX_C; //第一次MAX_C分配内存 int num_d1 = MAX_D; //预编译替换(分配内存)
int num_c1 = MAX_C; //之后MAX_C就不分配内存 return ;
}

  2.从语句使用:(const能避免一些宏define因为括号引起的错误)

 #define   MAX_D   10 + 20
const int MAX_C = + ;
.....
int num_d = MAX_D / ; //因为宏的特性预编译后num_d = 10 + 20 / 2
int num_c = MAX_C / ; //执行后num_c = 30 / 2;

  3.小结

  • 数据类型:cosnt修饰的变量有明确的类型,而宏没有明确的数据类型(不安全,但很灵活->很强大)
  • 安全方面:const修饰的变量会被编译器检查,而宏没有安全检查,可能会发生意外的错误(边界效应)
  • 内存分配:cosnt修饰的变量只会在第一次赋值时分配内存,节省空间,避免不必要的内存分配,同时提高效率,而宏是直接替换,每次替换后的变量都会分配内存 
  • 作用场所:const修饰的变量作用是在编译、运行过程中,而宏作用在预编译
  • 代码调试:cosnt方便调试,宏在预编译进行所以没法调试。

 三、const的使用

  1.修饰只读常量,不能被改变。改变报错。

  2.修饰一般变量(const的位置可以在类型说明符前或后)

 int const num=;
const int num=;

  3.修饰只读数组(const的位置可以在类型说明符前或后)

 int const num[]={, };
const int num[]={, };

  4.修饰指针(四种形式)

 const int *ptr;               //ptr可变,指向对象不能变
int const *ptr; //ptr可变,指向对象不能变
int * const ptr; //ptr不可变,指向对象可变
const int * const ptr; //ptr都不可变

  我也搞混淆了很多次,不过总结了一下,在分析就完全ok了。

  ①首先我们得知道const一次只能修饰一个变量

  ②然后我们得根据就近原则,所谓“近水楼台先得月”来判断哪个变量跟cosnt最近,是(*ptr)还是ptr。

  ③之前也有提到const的位置可以在类型说明符前或后。

 const int *ptr;               //const与*ptr近,与ptr远
int const *ptr; //const与*ptr近,与ptr远
int * const ptr; //const与ptr近,已经拆分了*ptr
const int * const ptr; //第二个const与ptr近,第一个const显然与(* const ptr)近

  5.修饰函数参数

 void Fun(const int *p);       //意义指针变量本身可变,p所指向的变量不可变

  ①告诉编译器传入参数不能改变,防止使用者的无意或错误的修改

  ②修饰指针传参,就是在声明函数内部不会改变这个指针所指向的内容。(一般是做函数输入参数)

  ③补充:这也可以只知道函数原型时可以大概去判断函数列表里的输入参数与输出参数

  6.修饰返回值

const int Fun (void);   //返回值不可被改变。

四、补充

  1.const常量可以被改变(gcc环境下)

 const int num = ;
int *p = (int *)# //强制类型转换来消除警告;
*p = ;
printf("num = %d.\n", num); //num = 10,const类型的变量被修改

  原因:

  ①const在c的规定中并未有明确规定,const修饰的变量存放在哪里

  ②在gcc环境下,const是通过编译器在编译的时候执行安全检查,在程序运行过程中并不会报错。

  ③内存的储存上,gcc把const类型的常量也放在了data段

  ④所以根据这些特性,通过强大的指针骗过编译器就可以改变了

五、总结

  1.const的合理使用能告诉编译器哪些变量不希望改变,防止无意的被修改,减少bug,也使代码更严谨。

  2.const的使用也是为读代码的人传递很有用的信息,间接或直接告诉使用者这个变量不应该被修改。


 作者:Devil-wei

出处:https://www.cnblogs.com/Devil-wei/

版权声明:本文版权归作者和博客园共有,转载请标注文章作者与出处

对const的总结与思考的更多相关文章

  1. iOS 宏(define)与常量(const)的正确使用

    在iOS开发中,经常用到宏定义,或用const修饰一些数据类型,经常有开发者不知怎么正确使用,导致项目中乱用宏与const修饰 你能区分下面的吗?知道什么时候用吗? #define HSCoder @ ...

  2. 【转】iOS 宏(define)与常量(const)的正确使用-- 不错

    原文网址:http://www.jianshu.com/p/f83335e036b5 在iOS开发中,经常用到宏定义,或用const修饰一些数据类型,经常有开发者不知怎么正确使用,导致项目中乱用宏与c ...

  3. API设计原则

    译序 Qt的设计水准在业界很有口碑,一致.易于掌握和强大的API是Qt最著名的优点之一.此文既是Qt官网上的API设计指导准则,也是Qt在API设计上的实践总结.虽然Qt用的是C++,但其中设计原则和 ...

  4. ES6 阮一峰阅读学习

    参考: ECMAScript6入门 就是随便看看,了解一下. 一.ECMAScript6简介 1. 什么是ECMAScript6? JavaScript语言的下一代标准.2015年6月发布,正式名称是 ...

  5. C++解析(4):引用的本质

    0.目录 1.引用的意义 2.特殊的引用 3.引用的本质 4.函数返回引用 5.小结 1.引用的意义 引用作为变量別名而存在,因此在一些场合可以代替指针 引用相对于指针来说具有更好的可读性和实用性 注 ...

  6. openssl 1.1.1 reference

    openssl 1.1.1 include/openssl aes.h: # define HEADER_AES_H aes.h: # define AES_ENCRYPT 1 aes.h: # de ...

  7. 近期学习es6后对变量提升及let和const的一点思考

    1.变量提升:(创建->初始化)-->赋值-->修改 就是说,以var声明的变量,它的声明会被提升到当前作用域的顶端(注意是变量声明提升,变量的赋值没有提升) //在if语句中也会提 ...

  8. 今天思考一个问题,PHP const和static的区别

    static关键字在类中是,描述一个成员是静态的,static能够限制外部的访问,因为static后的成员是属于类的,是不属于任何对象实例,其他类是无法访问的,只对类的实例共享,能一定程序对该成员尽心 ...

  9. C++中关于const的思考

    在学习C++的过程中,经常被什么时候使用const.为什么使用const以及怎么使用const关键字这样的问题所困扰,以下是我对const的使用总结. 1.值替代 使用#define的确单缺点,第一: ...

随机推荐

  1. MongoDb 集群不可用后SECONDARY节点强制启动

    机房意外断电断网不得不预防,下面模拟测试某机房断电断网,B机房断电断网后A机房可正常提供服务,A机房断电断网后可能需要强制重启继续提供服务了,目前查看数据都还在,暂时没验证是否有数据丢失,小试了一把. ...

  2. 如何优雅的使用 参数 is null而不导致全表扫描(破坏索引)

    相信大家在很多实际业务中(特别是后台系统)会使用到各种筛选条件来筛选结果集 首先添加测试数据 ), Age INT) go CREATE INDEX idx_age ON TempList (Age) ...

  3. Scala实现Try with resources自动关闭IO

    在处理数据库连接或者输入输出流等场景时,我们经常需要写一些非常繁琐又枯燥乏味的代码来关闭数据库连接或输入输出流. 例如数据库操作: def update(sql: String)(conn: Conn ...

  4. SpringBoot/SpringMVC文件下载方式

    本篇文章引用外网博客代码,共描述SpringMVC下三种文件下载方式,本人测试在SpringBoot(2.0以上版本)正常使用. 引用博客,强烈推荐https://www.boraji.com. pa ...

  5. spring设计模式_代理模式

    代理模式应该是Spring核心设计模式之一了 先说下代理模式特性: 1.有代理人和被代理人 2.对于被代理的人来说,这件事情是一定要做的,但是我又不想做,所有就找代理人来做. 3.需要获取到被代理人的 ...

  6. PMBook - 7.项目成本管理

    7.1 规划成本管理 7.1.1 规划成本管理:输入 7.1.1.1 项目章程 7.1.1.2 项目管理计划 7.1.1.3 事业环境因素 7.1.1.4 组织过程资产 7.1.2 规划成本管理:工具 ...

  7. Identity Server 4 预备知识 -- OAuth 2.0 简介

    OAuth 2.0 简介 OAuth有一些定义: OAuth 2.0是一个委托协议, 它可以让那些控制资源的人允许某个应用以代表他们来访问他们控制的资源, 注意是代表这些人, 而不是假冒或模仿这些人. ...

  8. Springboot 系列(七)Spring Boot web 开发之异常错误处理机制剖析

    前言 相信大家在刚开始体验 Springboot 的时候一定会经常碰到这个页面,也就是访问一个不存在的页面的默认返回页面. 如果是其他客户端请求,如接口测试工具,会默认返回JSON数据. { &quo ...

  9. 第三节:dingo/API 最新版 V2.0 之 Creating API Endpoints (连载)

    对于这篇文章的标题,其实,直译就是创建api端点.但是,真的很难懂,我还是写为API路由吧.每篇,文章,我都会全部去进行实践操作,力求写一个好点的教程. 本文英文地址——>https://git ...

  10. 我的python渗透测试工具箱之自制netcat

    此工具的目的是实现在目标主机上的文件传输,控制命令行的功能,主要逻辑依靠python的subprocess模块.`sys`模块和`getopt`模块. 知识准备 studin和studut studi ...