当前位置:主页 > 软件编程 > C代码 >

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

时间:2021-05-23 08:08:33 | 栏目:C代码 | 点击:

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指向的地址的唯一性,同时不会因操作该指针修改指向地址的值

总结

您可能感兴趣的文章:

相关文章