C语言中常用的一般包括const、static、extern、register和volatile这几个。这些是C语言标准中规定的关键词,所有的编译器都必须支持这些关键词,它们的作用如下:
1、const修饰的变量被称为常量,所谓常量,就是不能改变、不能再赋值的变量。
比如int a = 10,定义了一个变量a,并初始化为a = 10,在后续的代码中我们可以随时修改a的值的,可以通过a = 15把a的值修改为15。
但是如果使用const修饰了变量,比如const int a = 10或者int const a = 10,这时候a就是一个常量变量,它的值就固定为了初始化时的值10,后续代码如果出现了a = 15编译器就会报错告诉你a是一个常量,不能赋值。
有一点需要注意的是cons修饰的对象,对于普通变量而言,const修饰的就是变量,但是对于指针而言,const在不同的位置修饰的对象就不同了。比如const int *p或者int const *p和int * const p修饰的就是两个不同的对象,前者const int *p修饰的是整个(*p),也 就是指针p所指向的内存中的值是常量,是不能改变的,这种称为常量指针。如果定义了const int *p = &a;int a = 10;这时候就不能再通过*p = 15来改变a的值了,但是因为a并不是const修斯的变量,我们还是可以通过给a赋值的方式修改*p的值,如果a = 15,那 么*p = 15。有一点需要注意的是,p的值是可以修改的,因为const修饰的是*p并不是p,所以我们可以通过int b = 15,p = &b的方式修改*p的值。
这就引出了另一种修饰方式int * const p,这种称为指针常量,这时候const修饰的就是指针p,所以p的值就是不能改变的,如果有int * const p = &a,int a = 10,把么p就永远指向a所在的地址了,p = &b就是错误的。这时可以通过*p = 15和a = 15的方式修改*p的 值。
总结下来就是常量指针 const int *p表示*p的值不能修改,但是p的值可以修改。指针常量int * const p表示p的值是不能改变的,但是*p的值可以改变。
使用const的本意是希望被const修饰的值不被代码其他行为修改,但是当const修饰指针的时候,如果不注意逻辑关系,往往会造成const修饰的值被意外修改:
(1)、int a = 10;const int *p = &a,如果出现了a = 15,那么*p = 15
(2)、const int a = 10,int b = 15,const int *p = &a,如果出现了p = &b(或者p = p1,p1为指针,*p1 = 15),那么a = 10,*p = 15
2、static可以修饰变量和函数,static修饰变量的时候分两种情况
(1)、static修饰局部变量,自动初始化变量并延长变量的生存周期(跳出函数之后变量的值不会被释放修改),static int a;表示a是一个静态变量,并初始化为a = 0;普通的局部变量定义的时候不会初始化,它的值虽然大部分时候为0,但实际情况它可能是任 意值(分配的地址中的值)。
(2)、static修饰全局变量和函数,主要是限定全局变量和函数的作用域,被static修饰的全局变量和函数只能在当前源文件调用,其他源文件无法调用。
3、extern可以修饰变量和函数,它的作用申明变量和函数,告诉编译器这个变量和函数是在其他文件中定义的,要调用这个变量或者函数的时候就去其他文件查找。有一点需要注意的是,如果变量或者函数在其他文件中被static修饰了,extern就没法申明变量和函数。
4、register只能修饰局部变量,表示让编译器把这个局部变量放在寄存器当中,不要放在堆栈里,因为调用变量的时候MCU都是先把变量从堆栈中读到寄存器中再进行操作,这样直接放在寄存器中就可以节省时间。有一点需要注意,register只能修饰局部变量,因为
寄存器的数量是有限的,当寄存器用完了之后编译器还是会自动把变量放在堆栈区。
5、volatile可以修饰各种变量,它表示当前变量是随时可能改变的,告诉编译器调用这个变量的时候每次都去变量所在的地址读值而不是从寄存器中取值。
原创文章,作者:,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/271645.html