C++ | const修饰的变量

Posted 就良同学

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ | const修饰的变量相关的知识,希望对你有一定的参考价值。

01.const 概述

const 单词字面意思为常数,不变的。它是 c/c++中的一个关键字,是一个限定符,它用来限定一个变量不允许改变,它将一个对象转换成一个常量。

const int a = 10;
A = 100; //编译错误,const 是一个常量,不可修改

02.C/C++中 const 的区别

2.1 C 中的 const

常量的引进是在 c++早期版本中,当时标准 C 规范正在制定。那时,尽管 C 委员会决定在 C 中引入 const,但是,他们 c 中的 const 理解为”一个不能改变的普通变量”,也就是认为 const 应该是一个只读变量,既然是变量那么就会给 const 分配内存,并且在 c 中 const是一个全局只读变量,c 语言中 const 修饰的只读变量是外部连接的。

如果这么写:

const int arrSize = 10;
int arr[arrSize];

看似是一件合理的编码,但是这将得出一个错误。 因为 arrSize 占用某块内存,所以 C编译器不知道它在编译时的值是多少?

2.2 C++中的 const

在 c++中,一个 const 不必创建内存空间,而在 c 中,一个 const 总是需要一块内存空间。在 c++中,是否为 const 常量分配内存空间依赖于如何使用。一般说来,如果一个const 仅仅用来把一个名字用一个值代替(就像使用#define 一样),那么该存储局空间就不必创建
如果存储空间没有分配内存的话,在进行完数据类型检查后,为了代码更加有效,值也许会折叠到代码中。

这就是C++中的常量折叠:指const变量(即常量)值 放在编译器的符号表中 ,计算时编译器直接从表中取值,省去了访问内存的时间,从而达到了优化

不过,取一个 const 地址, 或者把它定义为 extern,则会为该 const 创建内存空间。在 c++中,出现在所有函数之外的 const 作用于整个文件(也就是说它在该文件外不可见),默认为内部连接,c++中其他的标识符一般默认为外部连接

2.3 C/C++中 const 异同总结

1)内存占用方面

C语言的const修饰的变量均占有内存空间;

C++的const修饰的变量有时占用内存空间,有时不占用内存。

①C语言的const修饰的变量不论是全局变量还是局部变量,均占用内存。

#include<stdio.h>

const int a = 10; //存储在静态区(全局区),占用内存

void test01()
	int *p;
	// a = 100; // error: 全局的const不能直接修改
	printf("a = %d\\n", a);
	p = (int *)&a;
	// *p = 100; // error: 全局的const不能间接修改
	printf("a = %d\\n", a);



void test02()
    const int b = 20; //存储在栈区,占用内存
    int *p;
	// b = 200 //  error: 局部的const不能直接修改
    printf("b = %d\\n", b);
    p = (int *)&b;
    *p = 200; //  局部的const可以间接修改
    printf("b = %d\\n", b);

②C++的const修饰的变量有时占用内存空间,有时不占用内存。

#include<iostream>
using namespace std;

const int aa = 10;

void test01()
	int* p;
	/* 在编译阶段,编译器将转为 cout << "aa=" << 10 << endl; */
	cout << "aa=" << aa << endl;

	const int bb = 20;
	p = (int*)&bb; // 此时会为bb分配内存
	*p = 300;

	/* 在编译阶段,编译器将转为 cout << "bb:" << 20 << endl; */
	cout << "bb:" << bb << endl;
	cout << "*p:" << *p << endl;

	cout << "bb的地址=" << &bb <<endl;
	cout << "p指向的地址=" << p << endl;


int main()
	test01();
    return 0;

输出:

aa=10
bb:20
*p:300
bb的地址=0019FED4
p指向的地址=0019FED4

小结:C++的const修饰的变量有时占用内存空间,有时不占用内存(发生常量折叠,且没有对变量进行取址运算时)。

对于基础数据类型,如果用一个变量初始化 const 变量,如果 const int a= b,那么也是会给 a 分配内存。

#include<iostream>
using namespace std;

int main()
	int b = 10;
	const int constA = b;
	int* p = (int*)&constA;
	*p = 300;
	cout << "constA:" << constA << endl;
	cout << "*p:" << *p << endl;

	cout << "constA的地址=" << &constA <<endl;
	cout << "p指向的地址=" << p << endl;
	return 0;

输出:

constA:300
*p:300
constA的地址=0019FF28
p指向的地址=0019FF28

③扩展:volatile关键字

C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量。volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。声明时语法:int volatile vInt; 当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。

即:用volatile 声明类型变量的时候,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

#include<iostream>
using namespace std;

void test01()
	int* p;
	volatile const int bb = 20; //volatile: 禁止优化

	p = (int*)&bb; // 此时会为bb分配内存
	*p = 300;

	cout << "bb=" << bb << endl;
	cout << "*p=" << *p << endl;

	cout << "bb的地址=" << &bb <<endl;
	cout << "p指向的地址=" << p << endl;


int main()
	test01();
	return 0;

注:C++中,为什么对volatile的变量进行取地址操作,会出现1这样的数值,而不是正常的逻辑地址?

https://www.zhihu.com/question/411562530

2)跨文件访问方面

C语言的const修饰的全局变量默认为外部连接。

C++的const修饰的变量默认为内部连接。

这是因为C++的const修饰的变量默认为内部连接,即作用域仅限当前文件。

如果想让 c++中的 const 具有外部连接,必须显示声明为: extern const int data = 99;

c++ const关键字总结

const在C++中的使用:

  • const对变量的修饰
  • cosnt对指针的修饰
  • const对函数的修饰

一. const对变量的修饰

  const int MAX_SIZE = 1024;
  这是最常见的用法,大家都没问题, const在定义的时候需要初始化。
  有两点需要注意一下:
  a) const变量默认是局部变量,如果需要全局访问,需要显示地extern
  b) const int MAX_SIZE = 1024 与 #define MAX_SIZE1024 貌似做了相同的事情,但是是完全不同的两个同意。
  #define作为宏定义是完全文本替换,而const MAX_SIZE是作为一个变量整体的。
  下面这段代码可以说得更清楚:
  const int MAX_SIZE = 1 << 10;// #define MAX_SIZE 1<<10
  cout << MAX_SIZE << std;

二. const对指针的修饰

  const int * a = &b; (1)
  int const * a = &b; (2)
  int * const a = &b; (3)
  const int * const a = &b; (4)
  (1)(2)的含义是相同的,表示指针所指的内存空间不可修改. *a = XXX;是非法的
  (3)表示指针不可修改,a++是非法的;
  (4)表示指针和指针内容都不可修改

三. const对函数的修饰

  void fun(const int &r) (1) 与int const相同
  void fun() const (2)
  const int fun() (3)
  (1) 函数的参数为const,表示函数不可修改参数的值
  (2) 函数加const后缀, 此时的函数为自定义结构(struct,class)的成员函数,表示该函数成员不可修改class的成员变量
  (3) 函数的返回结果为const
  表示返回的结果不可修改,返回结果只能赋值给const修饰的变量

经验:

  1)对const变量采用统一的编码风格能减少一些不必要的错误
  2)给函数传参时,尽量使用带const的引用方式
  3)返回结果迫不得已才使用const修饰

以上是关于C++ | const修饰的变量的主要内容,如果未能解决你的问题,请参考以下文章

C++:const用法总结

c++ const关键字总结

C++ const 修饰符

《挑战30天C++入门极限》入门教程:C++中的const限定修饰符

C++中const关键字的使用总结

C++ const,static,inline