C语言复习—static/const/volatile关键字

static/const/volatile关键字

static

先从C语言开始
1- static修饰代码块内部的变量(局部变量),改变了变量的存储类型,变量将从栈区转到静态区,不改变变量的属性和作用域。
2- static修饰局部变量,具有 “记忆性” 的特点,还可以延长它的生命周期。
3- 普通的局部变量是在栈上分配空间,因此每次调用函数时,分配的空间可能都不一样,但是static具有全局唯一性特点,每次调用都指向同一块空间,就造成了一个问题——不可重入性!!
4- static修饰代码块外部的变量(全局变量),或者修饰函数时,它将改变标识符的链接属性。也就是说只能在文本内部使用,限制了函数或者变量的对外可见性,不影响其存储类型和作用域。

对于C++来说
1- 修饰成员变量时,称为静态数据成员,它不属于某个对象,而是属于这个类,由所有对象所共享。
2- 静态数据成员在程序编译的时候已经分配好了内存,不占用类对象的内存空间,在程序运行结束才释放空间。
3- 只能在类内定义静态数据成员,在类外进行初始化,没有初始化则程序编译错误,如果初始化没有赋初值,则编译器自动赋初值为0。
4- 不能使用参数化列表进行静态数据成员的初始化,如果静态成员变量是私有的,则不能在类外访问。
5- 修饰成员函数时,静态成员函数的作用是处理静态数据成员,它不能调用类的非静态成员,因为静态成员函数没有this指针。
6- 非静态成员函数可以调用静态成员函数,在类加载时,编译器就为静态成员函数分配好空间了。
7- 最后静态成员是可以独立访问的,也就是说,无需创建任何对象实例就可以访问。

const

  • const修饰一个变量,意味着这个该变量里的数据可以被访问,但是不能被修改。说明这个变量具有常性,也称之为常变量。
  • 修饰规则:const离谁近,谁就不能被修改,如果const在最前面,则往后移一位,作用是等效的。
  • const修饰一个变量时,必须给这个变量初始化,否则后面就无法初始化。
  • const可以使编译器很自然的保护那些不希望被修改的参数。
  • 对于类的成员函数来说,有时候必须指定为const类型,作为一个常函数,不能修改类的成员变量。有时候返回值必须设为const类型,使其不为 “左值” 。
1.声明常变量,使得指定的变量不能被修改。
const int a = 5;     /*a的值一直为5,不能被改变*/
const int b; b = 10; /*b的值被赋值为10后,不能被改变*/
const int *ptr;      /*ptr为指向整型常量的指针,ptr的值可以修改,但不能修改其所>指向的值*/
int *const ptr;      /*ptr为指向整型的常量指针,ptr的值不能修改,但可以修改其所指>向的值*/
const int *const ptr;/*ptr为指向整型常量的常量指针,ptr及其指向的值都不能修改*/
2.修饰函数形参,使得形参在函数内不能被修改,表示输入参数。
如int fun(const int a);
int fun(const char *str);
3.修饰函数返回值,使得函数的返回值不能被修改。
const char *getstr(void);使用:const *str= getstr();
const int getint(void);  使用:const int a =getint();

volatile

 int i = 5;
 int a = i;
 ...
 int x = i;

如上面的代码,编译器发现在两次从i中获取数据的代码之间,没有对i进行操作,就直接把上次读的数据放在x中,而不是从i中重新获取,这就是编译器的优化

加上volatile关键字就可以防止编译器的优化。

在多线程中,如果两个线程都要访问某一个变量num(该变量的值会被改变)时,编译器会把num放入寄存器,以提高访问的效率,即使num所在内存中的值被改变了,寄存器也感应不感到。那么两个线程可能一个使用的是内存中的变量,一个使用的是寄存器中的变量,就会导致程序的错误执行。

加上volatile关键字,可以防止防止优化编译器将内存中的变量放入寄存器中,保证了内存的可见性。

3个经典volatile问题

1). 一个参数既可以是const还可以是volatile吗?解释为什么。
2). 一个指针可以是volatile 吗?解释为什么。
3). 下面的函数有什么错误:
int square(volatile int *ptr)
{
return *ptr * *ptr; //返回(*ptr)的平方
}

  1. 可以的,如果对于只读寄存器来说,如果它仅仅是volatile类型的话,可能还是会被意想不到的改变,加上const程序就不该试图去修改它。
  2. 可以的,尽管不常见,但是有个例子:当一个中断服务子程序企图去修改一个指向一个buffer指针的时候。
  3. 代码可以解释为
    int square(volatile int *ptr)
    {
    int a,b;
    a = *ptr;
    b = *ptr;
    return a*b;
    }

    因为*ptr可能会被意想不到的改变,所以得不到想要的结果。
    可以改为:
    long square(volatile int *ptr)
    {
    int a;
    a = *ptr;
    return a*a;
    }

猜你喜欢

转载自blog.csdn.net/qq_40840459/article/details/81219012