const和volatile修饰符
有两种限制符能够对变量的访问和修改进行控制:const和volatile。它们必须写在所需要限制的类型修饰符和类型名称之前。这类限制符被称为cv限制符(修饰符)。
const修饰符
const修饰符限定的变量将不能被你的程序所修改。(当然,一个const型的变量可以被赋予初值。)编译器将会把这种类型的变量(实际上经过限定符的限制它已经是通常所说的常量)存储在只读内存单元中。例如:
const int a=10;
表达式创建了一个整型的常量a,并且将a的初值初始化为10。程序将不能对常量a进行任何更改,不过你可以在其它不改变a的值的表达式中使用常量a。常量不能被任何显式的初始化或者依赖硬件的操作赋值。const修饰符可以防止做为实参传递给函数的指针指向的对象被函数修改。就是说,当一个指针被做为实参传递给函数的时候,函数就能够改变这个指针所指向的对象的值。但是如果在函数声明形式参数时就将对应的形参加上const修饰符,那么传递给函数对应形式参数的指针所指向的内容就不能被函数修改。例如,下面的程序中的sp_to_dash()函数功能是将一个字符串所有空格替换为‘-’显示出来。也就是说比如字符串是“this is a test”,那么屏幕上将会打印“this-is-a-test”。在形式参数声明的时候使用了const修饰符,确保了str指针所指向的字符串对象的值不会被函数修改。
#include <stdio.h>
void sp_to_dash( const char *str );
int main( void )
{
sp_to_dash( "this is a test" );
return 0;
}
void sp_to_dash( const char *str )
{
while( *str )
{
if( *str == '' printf( "%c", '-' );
else printf( "%c", *str );
str++;
{
}
如果将sp_to_dash()函数改写成如下的形式,那么字符串将会被修改,程序将无法通过编译。
/* This is wrong. */
void sp_to_dash( const char *str )
{
while( *str )
{
if( *str == '' *str = '-'; /* can't do this; str is const. */
printf( "%c", *str );
str++
}
}
许多标准库函数也在声明形式参数的时候使用了const修饰符。例如,strlen()函数原型为:
size_t strlen( const char *str );
将str指针定义为常量,能确保strlen()函数不会修改传递给str形参的指针所指向的字符串对象。通常,当一个函数不需要修改传递给它的指针所指向的对象的内容时,对应的形式参数都被声明为常量。我们还可以使用const修饰符来保证程序不会修改一个变量的值。不过有一点需要知道,常量可以被程序外的某些事物修改。比如硬件设备。尽管如此,通过用const限制变量称为常量的方式,我们至少可以证实是某些外部事件导致了变量的值发生改变。
volatile修饰符
使用volatile修饰符将会告诉编译器变量的值将有可能在程序没有显式指定的情况下发生改变。比如,一个全局变量可能被传递给一个系统时钟例程,用来跟踪系统时间。这样,该全局变量的值就可能在程序没有任何显式的赋值语句出现时也发生改变。在c语言和c++中,编译器常常会自动的对程序进行一些优化。如果一个变量没有在任何赋值语句的左侧出现,换言之,一个变量未在任何显式的赋值语句中出现,编译器会假定这个变量的值是恒定不变的。那么在程序中用到这个变量的地方,将会自动的使用变量的初值,而不会每一次都重复对变量的值进行检查。有些编译器还会在编译过程中改变表达式的赋值顺序。volatile修饰符将会阻止这些错误。
有时,const和volatile修饰符可以同时使用。例如,假定0x30是某个端口的值,它只能被外部硬件状况所更改,如下的声明可以防止任何副作用发生:
const volatile char *port = ( const volatile char* ) 0x30;