c语言学习笔记(3)const和volatile以及const volatile int i=0分析

摘要: 分析了const和volatile的意义,const修饰数组,指针,函数参数和返回值的用法,最后解释了const volatile int i=0这个问题。


一、const修饰变量的意义

    在c语言中,const修饰的是只读变量,并不是一个常量,本质还是一个变量。const修饰的变量会占用内存空间,本质上const只对编译器有用,它告诉编译器,这个变量是只读的,不能对其进行左值操作,运行时没用。

    如果要对const修饰的只读变量赋值,可以使用指针,取地址操作符,因为它占用了内存空间,我们可以往该空间的地址里面写值,例如:

#include 
int main(void)
{
    constint cc=1;
    int*p = (int*)&cc;
    printf("%d\n",cc);
    *p= 3;
    printf("%d\n",cc);
   
    return0;
    }

这里我们对const修饰的只读变量进行了修改,打印出的结果如下:


假设不使用*p=3这一句,而是直接对cc赋值,cc=3,编译的时候就会报错,说向只读变量赋值。


二、const修饰数组

    在c语言中,const修饰的数组是只读的,const修饰的数组空间不可被改变。


三、const修饰指针

    这里有国嵌总结了一组使用方法和判断技巧,贴出来如下:

    constint* p; //p可变,p指向的内容不可变
    int const* p; //p可变,p指向的内容不可变
    int* const p; //p不可变,p指向的内容可变
    const int* const p; //p和p指向的内容都不可变
    口诀:左数右指
    当const出现在*号左边时指针指向的数据为常量
    当const出现在*后右边时指针本身为常量

    这个方法还是很好记的,在定义的时候,我们只需要看const和*的位置,const在左边的时候指向的数据为常量,那么去赋值就会出错,在右边的时候指针本身是常量,不可以给这个指针赋值。这里实验就不贴出来,可以自己顶一个变量a,一个指针p,然后改变const和*的位置,试着往里写数据读数据,自然就会理解。


四、const修饰函数参数和返回值

    const修饰函数参数,表示在函数体内,不希望改变参数的值。

    const修饰函数的返回值,表示返回值不可变,多用于返回指针。

    这里如果函数被const修饰,在读取返回值的时候,最好还是把左值也定义为const类型的。


五、volatile的意义

    volatile在编写驱动,移植u-boot的时候,可以看到很多寄存器前面都加了volatile,这是为什么呢?因为加了volatile之后,会告诉我们的编译器,不要去优化它,要每次都从里面读取变量的值,因为我们这个变量,可能因为硬件中断,多线程访问或者其他位置因素,被更改,即使我们没有使用比如a=1这样的左值方法去改变它,它也会因为上述原因被改变,如果我们的编译器进行优化了,就会将这个a变为第一次读到的值传给下面的变量,这样就会引起错误。

    比如我们在移植dm9000网卡驱动的时候,在dm9000_init函数里面就会对bwscon使用这个定义,因为网卡的寄存器的值会改变,如果编译器优化了,那么我们就无法获得正确的初始化:

     unsignedintoldval_bwscon  =   *(volatile unsigned int *)S3C2410_BWSCON;


六、const volatile int i=0分析

    这里用const和volatile同时修饰i是没有问题的,因为他们的使用并不矛盾:

    “const”含义是“请做为常量使用”,而并非“放心吧,那肯定是个常量”。
    “volatile”的含义是“请不要做没谱的优化,这个值可能变掉的”,而并非“你可以修改这个值”。

    所以这里的i的属性是在本程序中,i应该是只读的,不应该被修改的,但是它也可能被外部的例如中断,共享的线程通过某种方式修改,所以这里也不该被编译器优化,虽然它是只读的不该被修改的,但是它还是会改变,我们在本程序中使用的时候,还是要每次都去读它的值,这是一种“双重保险”。

    我认为这个问题要结合实际的使用场合来回答才更贴切,举个例子:在程序A中,我们要访问一个只读寄存器c,这时候修饰它为const,但是在程序B中,我们又会改变c的值,为了在A中避免编译优化造成程序逻辑错误,我们将其修饰为volatile,这样c就具有了双重属性。

    网上别人的解答如下:

    const和volatile放在一起的意义在于:

  (1)本程序段中不能对a作修改,任何修改都是非法的,或者至少是粗心,编译器应该报错,防止这种粗心;
  (2)另一个程序段则完全有可能修改,因此编译器最好不要做太激进的优化。

    这篇帖子就总结到这里吧,如有不正确的地方还请指出,大家共同进步!

你可能感兴趣的:(C)