#1. Const
ANSI C 允许你声明常量,常量的样子和变量完全一样,只是它们的值不能修改,你可以使用 const 关键字来声明常量
int const a;
const int a;
这两条语句,都把 a 声明为一个整型常量,它的值不能被修改,所以你无法把任何值赋值给它,如此一来,怎么样才能让它一开始拥有一个值呢?有两种办法:
- 声明时就对它进行初始化
int const a = 5;
const int a = 5;
- 函数中声明为 const 的形式参数在函数被调用时会得到实参的值
void function( const int a ){
...
}
void main( void ){
int a = 10;
function( a );
}
##1.1. 常量指针与指针常量
int *p;
p 是一个普通的指向整型变量的指针,而变量
int const *p;
const int *p;
则是一个常量指针,你可以修改指针本身的值,但是不能通过指针 p 修改它所指向的呢个值(可以通过其他引用修改 p 指向的那个值),例如:
int a = 5;
int b = 5;
int const *p = &a;
//如下 3 种情况:
1. p = &b;//正确,可以修改指针 p 本身的值
2. a = 10;//正确,可以通过其他引用修改 p 指向的那个值
3. *p = 10;//错误语法,试图通过常量指针 p 修改 p 指向的那个值
指针常量声明如下
int * const p;
p 本身的值不允许修改,但是可以修改 p 指向的那个值,例如:
int a = 5;
int b = 5;
int * const p = &a;
//如下 2 种情况
1. p = &b;//语法错误,试图修改 p 本身的值
2. *p = 10;//正确,可以修改 p 指向的那个值
区分常量指针与指针常量的关键在于星号的位置,如果把 * 修饰符读作指针,把 const 修饰符读作常量:
int const *p;//常量指针
const int *p;//常量指针
int *const p;//指针常量
指向常量的常指针,无论是指针本身还是指针指向的那个值,都不允许被修改,声明如下:
int const * const p;
const int * const p;
如果const和volatile关键字的后面紧邻类型说明符如(int、long),那么它作用于类型说明符,在其他情况下,const和colatile关键字作用于它左边紧邻的指针星号
##1.2. Const修饰函数参数
防止修改指针指向的那个值,如果函数体内试图修改 p 指向的那个值,编译器将指出错误:
void function( const int *p ){
*p = 10;//错误
}
防止修改指针本身的值,如果函数体内试图修改 p 本身的值,编译器将指出错误:
void function(int * const p){
int a = 5;
p = &a;//错误
}
防止修改指针本身的值+指针指向的那个值,否则编译器将指出错误:
void function( int const *const p){
int a = 5;
*p = 10;//错误
p = &a;//错误
}
void function( const int *const p);//同上
##1.3. Const修饰函数返回值
如果给以“指针传递”方式的函数返回值加 const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加 const 修饰的同类型指针。
const char *GetString( void );
char *str = getString();//错误
char *const str = GetString();//错误
const char *str = GetString();//正确
char const *str = GetString();//正确
##1.4. Const与#define
#define 指令是另一种创建名字常量的机制, 例如:
#define MAX 50
int const MAX = 50;
在这种情况下,使用 #define 比使用 Const 变量更好,因为只要允许使用字面值常量的地方都可以使用前者,比如数组的长度,Const 变量只能用于允许使用变量的地方,Const 与预编译指令相比,有如下优点:
- 预编译指令只是对值进行简单的替换,不能进行类型检查
- 可以保护被修饰的东西,防止意外修改,增强程序的健壮性
- 编译器通常不为普通 const 常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高