C/C++ 中const关键字的用法小结

C++中的const关键字的用法非常灵活,而使用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 关键字后这个常量就不可以再赋值了!

C语言中不是有#define吗,干嘛还要用const呢,我想事物的存在一定有它自己的道理,所以说const的存在一定有它的合理性,与预编译指令相比,const修饰符有以下的优点:

1、预编译指令只是对值进行简单的替换,不能进行类型检查

2、可以保护被修饰的东西,防止意外修改,增强程序的健壮性

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

(以上三点摘抄自:https://www.jb51.net/article/70831.htm)

const 的应用

1 定义常量

 const int a=5;
 int const a=5;

两种用法是一样的,这里变量 a 在第一次定义时复制后,在程序运行中就不可再赋值改变了;

例如:

 int main (int argc,char* argv)
 {
 const int a=5;

 int const b=5;

 a=3; //编译时将会报错,常量不可修改
 b=8;//编译时将会报错,常量不可修改
 }

const用于修饰常量静态字符串,

例如:

const char* Str="ABCDEFGH";

此时 const修饰过的str就是常量 我们不可更改Str的值 如 Str[3]='H'; 这时候是错误的,

2 常量指针与指针常量

很多人往往分不清这两者的形态,

常量指针:

const int* pv;

int const* pv;

两种定义方式一样,都是定义一个常量指针;即不可通过这个指针修改所指向地址的值;但是所指向的地址的值是可以通过其他变量指针修改的;

但是常量指针可以赋值新的指向地址;

例如:

 int main (int argc,char* argv)

  { 

   int a=5;

   int b=7;

   const int* m=&a;

   int const* n=&b;

   int* p = n;//把常量指针 n 指向的地址赋给p;

   *m=3; //编译时将会报错,常量指针不可修改所指向的地址的值

   *n=8;//编译时将会报错,常量指针不可修改所指向的地址的值

   *p = 9; //编译无措,可以通过变量指针修改常量指针所指向的地址的值

   m=&b; //编译无措,常量指针可以修改所指向的地址

   n=&a; //编译无措,常量指针可以修改所指向的地址

   }

指针常量

int* const pv;

是指这个指针指向的地址不可在改变,但指向的地址的值可以再改变;(指针常量是指指针本身是个常量,不能在指向其他的地址)

 int main(int argc,char* argv)

  { 

  int a=5; 

  int b=7; 

  int* const m=&a; 

  *m =8; //编译无措 指针常量可以通过该指针修改所指向的地址的值

  m = &b; //编译出错 指针常量不可修改所指向想的地址

  }

指向常量的常指针

常量指针结合指针常量 即指向常量的常指针 表示指针本身和指针所指向的地址在定义时赋值后都不可再改变;

定义如下:

const int* const p;

那么如何来区分常量指针和指针常量呢?

这就要明白关键字的结合优先级了,

如:const int* p;

以*优先级最高,先和int 结合 得到 " int* " (读作整形指针) 然后(int*)和 const 结合得到 " const(int*)" (读作常量指针) ,然后才和p结合得到"(const(int*))p" (读作常量指针p),

int* const p;

同理,以*优先级最高,先和int结合得到"int*"(读作整形指针),然后(int*)和const结合得到"(int*)(const)"(读作指针常量),最后才和p结合得到"(int*)(const)p"(读作指针常量p)

3 常量函数

常见的定义方式

 class AA
 {
 public:
 void mf_Fun1()
 {
  int b=10;
  num=b;
 }
 void mf_Fun2() const
 {
  cout<<num; //编译无措,只读取成员变量
  num+=15; //错误 const 函数不可修改其成员变量,只可读取
 }
 }
int main()
{
 AA a1;
 const AA a2; //注意这里的const关键字
 a2.mf_Fun2();
 a2.mf_Fun1(); // 错误,const的实例对象 不能访问非const的函数
}

在类成员函数的声明和定义中, const的函数不能对其数据成员进行修改操作。 const的对象,不能引用非const的成员函数。

这儿的const就是说这个函数操作不会对变量或是对象之类的值有影响 比如、有一个human类 ,现在要得到某个human类对象A的age 那么肯定是不会因为想得到这个值而改变了age的大小,那么就可以写一个函数int getAge()const这样就好 这么做是为了防止在函数中对不应该在这里改变的量不小心进行了改变 (抄录自 https://zhidao.baidu.com/question/1702736835898870060.html)

4 在什么情况下需要用到Const关键字?

4.1 修饰函数的参数

根据常量指针与指针常量,const修饰函数的参数也是分为三种情况

1、防止修改指针指向的内容

void StringCopy(char *strDestination, const char *strSource);

其中 strSource 是输入参数,strDestination 是输出参数。给 strSource 加上 const 修饰后,如果函数体内的语句试图改动 strSource 的内容,编译器将指出错误。

2、防止修改指针指向的地址

void swap ( int * const p1 , int * const p2 )

指针p1和指针p2指向的地址都不能修改。

3、以上两种的结合。

4.2 修饰函数的返回值

如果给以“指针传递”方式的函数返回值加 const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。 例如函数

const char * GetString(void);

如下语句将出现编译错误:

char *str = GetString();

正确的用法是

const char *str = GetString();

4.3 修饰全局变量

全局变量的作用域是整个文件,我们应该尽量避免使用全局变量,因为一旦有一个函数改变了全局变量的值,它也会影响到其他引用这个变量的函数,

导致除了bug后很难发现,如果一定要用全局变量,我们应该尽量的使用const修饰符进行修饰,这样防止不必要的人为修改,使用的方法与局部变量是相同的。

4.4 寄存器变量定义和寄存器读取

例如:

uint32_t* R0 =(uint32*)0x400F00FF; //定义一个地址为0x400F00FF的32bit寄存器变量

正确的定义方法:

uint32_t* const R0 =(uint32*)0x400F00FF; //定义一个指针常量R0指向地址为0x400F00FF的寄存器 这样就保证变量R0指向的地址的唯一性,

若是指向一个只读寄存器则应该按如下定义:

const uint32_t* const R0 =(uint32*)0x400F00FF; //定义一个指向常量的常指针 R0 指向地址为0x400F00FF的只读寄存器,这样就保证变量R0指向的地址的唯一性,同时不会因操作该指针修改指向地址的值

总结

到此这篇关于C/C++ 中const关键字的用法小结的文章就介绍到这了,更多相关C/C++ const关键字内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解C++中的const关键字及与C语言中const的区别

    const对象默认为文件的局部变量,与其他变量不同,除非特别说明,在全局作用域的const变量时定义该对象的文件局部变量.此变量只存在于那个文件中中,不能别其他文件访问.要是const变量能在其他文件中访问,必须显示的指定extern(c中也是)   当你只在定义该const常量的文件中使用该常量时,c++不给你的const常量分配空间--这也是c++的一种优化措施,没有必要浪费内存空间来存储一个常量,此时const int c = 0:相当于#define c 0:    当在当前文件之外使用

  • 详解C/C++中const关键字的用法及其与宏常量的比较

    1.const关键字的性质 简单来说:const关键字修饰的变量具有常属性. 即它所修饰的变量不能被修改. 2.修饰局部变量 const int a = 10; int const b = 20; 这两种写法是等价的,都是表示变量的值不能被改变,需要注意的是,用const修饰变量时,一定要给变量初始化,否则之后就不能再进行赋值了,而且编译器也不允许不赋初值的写法: 在C++中不赋初值的表达一写出来,编译器即报错,且编译不通过. 在C中不赋初值的表达写出来时不报错,编译时只有警告,编译可以通过.而

  • C++ const关键字的实例用法

    C++中的const更像编译阶段的#define const int m = 10; int n = m; 变量是要占用内存的,即使被const修饰也不例外.m,n两个变量占用不同的内存,int n = m:表示将m的值赋给n. 在C语言中,编译器会先到m所在的内存取出一份数据,再将这份数据赋给n: 在C++中,编译器会直接将10赋给m,没有读取内存的过程,和int n = 10效果一样. 在C++中的常量更类似于#define命令,是一个值替换的过程,只不过#define是在预处理阶段替换,而

  • C/C++中static,const,inline三种关键字详细总结

    一.关于staticstatic 是C++中很常用的修饰符,它被用来控制变量的存储方式和可见性,下面我将从 static 修饰符的产生原因.作用谈起,全面分析static 修饰符的实质. static 的两大作用: 一.控制存储方式 static被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间. 引出原因:函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保

  • C++语言const 关键字使用方法图文详解

    之前一直在学习C/C++,关于const的使用,这里出现一点,那里出现一点.知识用时方恨少,这一段时间正好各种笔试题,其中关于const的用法也是层出不穷,所以疲于在书本上各种翻,这里汇总一下,加深自己的印象的同时,也方便以后查阅和学习.菜鸟一个,若有错误,望指正! const关键字 常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的.不管出现在任何上下文都是为这个目的而服务的. const使用方法 定义const对象 const修饰符可以把对象转变成常数对象,意

  • C++编程中的const关键字常见用法总结

    1.定义常量 (1)const修饰变量,以下两种定义形式在本质上是一样的.它的含义是:const修饰的类型为TYPE的变量value是不可变的. TYPE const ValueName = value; const TYPE ValueName = value; (2)将const改为外部连接,作用于扩大至全局,编译时会分配内存,并且可以不进行初始化,仅仅作为声明,编译器认为在程序其他地方进行了定义. extend const int ValueName = value; 2.指针使用CONS

  • C++常对象精讲_const关键字的用法

    const关键字: 用const修饰的定义对象称为常对象: 用const修饰的声明成员函数称为常成员函数: 用const修饰的声明数据成员称为常数据成员. 变量或对象被 const修饰后其值不能被更新.因此被const修饰的变量或对象必须要进行初始化. 常对象说明:常对象是指对象的数据成员的值在对象被调用时不能被改变.常对象必须进行初始化,且不能被更新.不能通过常对象调用普通成员函数,但是可以通过普通对象调用常成员函数.常对象只能调用常成员函数.常对象的声明如下: const       <类名

  • C/C++ 中const关键字的用法小结

    C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性. Const作用 NO. 作用 说明 参考 1 可以定义const常量 const int Max = 100; 2 便于进行类型检查 const常量有数据类型,而宏常量没有数据类型.编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误 void f(const int i) { ---} //对传入的参数进行类型检查,不匹配进行提示 3 可以保护被修

  • c#多线程中Lock()关键字的用法小结

    本文介绍C# lock关键字,C#提供了一个关键字lock,它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待. 每个线程都有自己的资源,但是代码区是共享的,即每个线程都可以执行相同的函数.这可能带来的问题就是几个线程同时执行一个函数,导致数据的混乱,产生不可预料的结果,因此我们必须避免这种情况的发生. 其中,lock是一种比较好用的简单的线程同步方式,它是通过为给定对象获取互斥锁来实现同步的.它可以保证当一个线程在关键

  • C++示例讲解friend static const关键字的用法

    目录 一.友元函数 1.1重载operator<< 1.2友元函数 1.3友元类 二.关键字const 2.1const修饰类的成员函数 三.关键字static 3.1static类成员 3.2面试题 总结 一.友元函数 1.1重载operator<< 问题:现在我们尝试去重载operator<<,然后发现我们没办法将operator<<重载成成员函数.因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置.this指针默认是第一个参数也就是左操

  • C语言const关键字的用法详解

    目录 1 介绍 1.1 const修饰变量 1.2 const修饰数组 1.3 const修饰指针 1.4 const修饰函数参数 2 const对程序的影响 3 总结 1 介绍 const关键字是constant的缩写,翻译为常量.常数.在C语言中const的作用很强大,它可以修饰变量.数组.指针.函数参数等. 1.1 const修饰变量 const修饰变量,表示希望此变量具有只读性,防止被直接直接修改. //const关键字是constant的缩写,翻译为常量.常数. //在C语言中cons

  • mybatis 中 foreach collection的用法小结(三种)

    foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有 item,index,collection,open,separator,close. item表示集合中每一个元素进行迭代时的别名,     index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,     open表示该语句以什么开始,     separator表示在每次进行迭代之间以什么符号作为分隔 符,     close表示以什么结束. 在使用foreach的时候

  • MySQL中ESCAPE关键字的用法详解

    MySQL转义 转义即表示转义字符原来的语义,一个转义字符的目的是开始一个字符序列,使得转义字符开头的该字符序列具有不同于该字符序列单独出现时的语义. MySQL中,转义字符以"\"开头,编程中常见的转义字符,在MySQL均是有效的,在此不做赘述和讨论.在此,主要通过"%" 和 "_"来对ESCAPE关键字的作用进行说明. %:匹配任意多个字符. _:匹配单一字符. 如果我们要匹配"%"或者"_"时,就必须

  • C#中AutoResetEvent控制线程用法小结

    目录 AutoResetEvent主要方法及实践 第二种方法Semaphore 第三种方法,约定每个线程只干自己的事 第四种方法 Mutex 本文主要来自一道面试题,由于之前对AutoResetEvent的概念比较模糊(即使已经使用过了).面试题题目很简洁:两个线程交替打印0~100的奇偶数.你可以先动手试试,我主要是尝试在一个方法里面完成这个任务. 注: Suspend,Resume来控制线程已经在.net framework2.0被淘汰了,原因就是挂起之后,但因为异常而没有及时恢复,如果占用

  • Python argparse中的action=store_true用法小结

    目录 Python argparse中的action=store_true用法 前言 示例 官方文档 多了解一点儿 自定义 小结 思考 补充:python库Argparse中的可选参数设置 action=‘store_true‘ 的用法 一.没有default 二.有default Python argparse中的action=store_true用法 前言 Python的命令行参数解析模块学习. 示例 参数解析模块支持action参数,这个参数可以设置为’store_true’.‘store

随机推荐