C++基础知识之"const"

fengjingtu

const基础知识

最初,我们队const的基础理解就是只读。他所修饰变量是不能被修改的。

我们看一下他修饰变量和指针时候的使用:

1
2
3
4
5
6
7
8
9
10
11
const int a;
int const b;
//const在int前后都可以,代表一个常整型数

const int *c;
int const *c;
//这两种写法const都在*的左边,表示指针指向的内容不能变。
int * const d;
//这种写法const都在*的右边,表示指针本身不能改变。
const int * const e ;
//表示指针指向的内容不能变,指针本身也不能改变。

合理的利用const,指针做函数参数,可以有效的提高代码可读性,减少bug;清楚的分清参数的输入和输出特性。这些都是使用const的好处。

事实上我们应该尽量多使用const。

C中的冒牌货

理解一下下面的C语言代码:

1
2
3
4
5
6
7
8
9
10

int main()
{
const int a = 10;
int *p = (int*)&a;
printf("a===>%d\n", a);
*p = 11;
printf("a===>%d\n", a);
return 0;
}

我们看到a是const定义的,但是它却可以改变,因为我们使用了指针,所以我们称C语言中的const是“冒牌货”,因为它没有做到我们的想要的,变量不能改变的需求。

而在C++中,输出都是10;

原因是:

C++编译器对const常量的处理,当碰见常量声明时,将常量放入符号表中,编译过程中若发现使用常量则直接以符号表中的值替换。如果编译过程中若发现对const使用了extern或者&操作符,则给对应的常量分配存储空间,这是一种兼容C的表现。C++编译器虽然可能为const常量分配空间,但不会使用其存储空间中的值。这就是为什么第二次输出还是10,因为他取的是符号表中的。

const声明的变量在符号表中,这导致了下面的情况

1
2
int &a = 1;//错误,a是变量,要引用变量。
const int &a = 10;//正确,a是常量,可以引用常量。

结论:

C语言中const变量是只读变量,有自己的存储空间

C++中的const常量可能分配存储空间,也可能不分配存储空间 ;当const常量为全局,并且需要在其它文件中使用;当使用&操作符取const常量的地址时会分配。

const和#define相同之处

C++中的const修饰的,是一个真正的常量,而不是C中变量(只读)。

在const修饰的常量编译期间,就已经确定下来了。这是C++中的const和#deifne的相同之处。

1
2
3
4
#define N 10 
const int a = 1;
int array[a = {0};
int array2[N] = {0};

const和#define不同之处

const常量是由编译器处理的,提供类型检查和作用域检查

宏定义由预处理器处理,单纯的文本替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

void fun1()
{
#define a 10
const int b = 20;
//#undef a # undef
}

void fun2()
{
printf("a = %d\n", a);//a=10,因为在fun1中有define
//printf("b = %d\n", b);//b没有定义,因为在fun1的定义不能起作用。
}

int main()
{
fun1();
fun2();
return 0;
}

练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <cstring>

void const_demo1()
{
int const a = 5;//必须初始化
const int b = 6;//a和b的定义方式等价。
const int *c = &a;//c所指向的内存空间不能通过c来改变,即*c不能为左值。
int * const d = (int *)&b;
//d只能指向b的内存空间,d不能作为左值。
//a=7;//error
//b=8;//error
//*c=9;//error
c = NULL;
*d = 10;
//d=NULL;//error
printf("a=%d,b=%d,*d=%d", a, b, *d);
//如果是C语言编译器,此处的b会是10
//C++编译器本来将ab都放在符号表中,不分配内存。
//因为下文对他们有区地址操作,所以又开辟了新的内存
//同样如果const变量在其他文件中被引用的话,也会开辟新的内存
return;
}

void const_demo2()
{
const int a = 1;
const int b = 2;
int arr[a + b] = { 0 };
//C++中的const是真的常量,不是C语言中只读变量。C语言中不可以,但linux内核中可以
int i;

for (i = 0; i<(a + b); i++)
{
printf("array[%d]=%d ", i, arr[i]);
}
return;
}

//const和define的不同之处:
//const有作用域和变量类型检查,由编译器处理,define由预处理器处理

void const_demo3()
{
#define A 10
const int B = 20;
}
void const_demo4()
{
printf("A=%d", A);
//printf("B=%d",B);//error,无法取得const_demo3()中的数据
return;
}
int main_const()
{
//const_demo1();
const_demo4();
return 0;
}
/*
C语言中的const变量
C语言中const变量是只读变量,有自己的存储空间
C++中的const常量
可能分配存储空间,也可能不分配存储空间
当const常量为全局,并且需要在其它文件中使用,会分配存储空间
当使用&操作符,取const常量的地址时,会分配存储空间
当const int &a = 10; const修饰引用时,也会分配存储空间
*/