C语言中关键字auto、static、register、extern、volatile、restrict的作用

auto:
(1):auto关键字在C语言中只有一个作用,那就是修饰局部变量。
(2):auto修饰局部变量,表示这个局部变量时自动局部变量,自动局部变量分配在栈上。(既然是分配在栈上,说明他如果不初始化的话那么值就是随机的....) 
(3):平时定义局部变量时就是定义的auto的,只是省略了auto关键字而已。可见,auto的局部变量其实就是默认定义的普通的局部变量。


static:
(1):static关键字在C语言中有2种用法,而且这两种用法彼此没有关联、完全独立的。其实当年本应该多发明一个关键字,但是C语言的作者觉得关键字太多不好管理,于是给static增加了一种用法,导致static一个关键字居然有两种截然不同的含义。
(2):static的第一种用法是:用来修饰局部变量,形成静态局部变量。静态局部变量和 非静态区别变量的区别。本质区别是存储类不同(存储类不
同就衍生出很多不同):非静态局部变量存储在栈上(auto),而静态局部变量分配在数据段或者是bss段。如果显示初始化为0则在数据段,如果没有
显示初始化为0则存在BSS段。
(3):static的第二种用法是:用来修饰全局变量,形成静态全局变量。静态全局变量和非静态全局变量的区别。区别是在连接属性不同。
分析:
(1):静态局部变量在存储类方面和全局变量一样。
(2):静态局部变量在生命周期方面和全局变量一样。
(3):静态局部变量和全局变量的区别是:作用域、生命周期。静态局部变量作用域是代码块作用域(和普通局部变量是一样的)、连接属性
是无连接;全局变量作用域是文件作用域(和函数的作用域是一样的)、连接属性方面是外连接。




register:
(1):register关键字不常用,也只有一个作用,那就是:用register修饰的变量编译器会尽量把它分配子寄存器中。(平时分配的一般变量都是在内存中)。分配在寄存器中用法是一样的,但是读写效率会高很多。所以说register修饰的变量用在那种变量被反复高频率的使用,通过改善这个变量的访问详聊可以极大的提升程序运行效率。所以说regis是一种极致提升程序运行效率的手段。
(2):在uboot中用到了一个register类型的变量,gd这个变量是用来存uboot的全局变量的(gd就是global data)。因为这个全局变量在整个uboot中到处都被访问,所以定义成register的。
(3):平常写代码要被定义成register这种情况很少,一般慎用。
(4):register编译器只能承诺尽量将register修饰的变量放在寄存器中,但是不保证一定放在寄存器中。主要原因是因为寄存器数量有限,不一定有用。


extern:
(1):extern主要用来声明全局变量,声明的目的主要是在a.c中定义全局变量而在b.c中使用该变量。
(2):C语言中冲虚的编译时以单个.C文件为单位的,因此在编译a.c时只考虑a.c中的内容(不会考虑b.c的内容),这就是导致a.c中使用了b.c中定义的变量时在编译时报错。解决方案是声明。
(3):应该在a.c中使用此变量之前先声明,声明就是告诉a.c我在别的文件中定义了该变量,并且它的原型和声明的一样,将来在连接的时候连接器会在别的.o文件中找到这个同名变量。此变量在a.c中声明的时候不能够加初始化。


volatile:
(1):volatile字面意思就是可变的、易变的。C语言中volatile用来修饰一个变量,表示这个变量,表示这个变量可以被编译器之外的东西改变。编译器之内的意思是变量值的改变是代码的作用,编译器之外的改变不是代码造成的,或者不是当前代码造成的,编译器在编译当前代码时无法预知。譬如说在中断处理程序isr中更改了这个变量的值,譬如说多线程中别的线程更改了这个变量的值,譬如说硬件自动更改了这个变量的值(一般这个变量是一个寄存器的值)。
(2):以上说的三种情况(中断isr中引用的变量,多线程中公用的变量,硬件会更改的变量)都是我们编译器在编译时无法预知的更改,此时我们应该使用volatile告诉编译器,这个变量属于这种情况--可变的、易变的。编译器在遇到volatile修饰的变量时就不会丢该变量的访问进行优化,就不会出现错误。


(3):编译器的优化在一般情况下非常好,可以帮助提升程序效率。但是特殊情况(volatile)除外。比如说a=3;b=a;c=b;在无优化的情况下内存要读三次、写三次;如果有优化的话:内存读一次,写三次就可以了优化成a=b=c=3。如果在执行a=3之后程序中断来临,此时将a=10;那么中断结束后:b的值为10(编译器未优化),b=3(编译器优化)。此时优化会带来错误,并且这种错误很难被发现。
如果定义变量时变量会被中断等改变,则需要声明成volatile。
(4):volatile是程序猿意识到需要volatile然后在定义变量时加上了volatile。如果你遇到了应该加volatile的情况而没有加程序可能会被错误的优化。如果不应该加volatile而加了的情况程序不会出错,知识降低了效率。所以我们对于volatile的态度应该是:正确区分,该加的时候加,不加的时候不加,如果不能确定该不该加,为了保险起见就加上。


restrict
(1):在C99中才支持的,所以很多延续了c89的编译器是不支持restrict。gcc支持。
(2):restrict也是和编译器的行为特征有关的。
(3):只用来修饰指针,不能修饰普通变量。概括的说,关键字restrict只用于限定指针;该关键字用于告知编译器,所有修改该指针所指向内容的操作全部都是基于(base on)该指针的,即不存在其它进行修改操作的途径;这样的后果是帮助编译器进行更好的代码优化,生成更有效率的汇编代码。
举个例子:
int fuc1(int *x,int *y)
{
*x = 0;
*y = 1;
return *x;
}
很显然函数fuc1()的返回值是0,除非参数x和y的值相同。可以想象,99%的情况下该函数都会返回0而不是1。然而编译起必须保证生成100%正确的代码,因此,编译器不能将原有代码替换成下面的更优版本.
int fuc1(int* x, int* y)
{
*x = 0;
*y = 1;
return 0;
}
如果加上了restrict关键字的话:
int fuc1(restrict int *x,restrict int *y)
{
*x = 0;
*y = 1;
return *x;
}
此时,由于指针 x 是修改 *x的唯一途径,编译起可以确认 “*y=1; ”这行代码不会修改 *x的内容,因此可以安全的优化为
int fuc1(restrict int* x,restrict  int* y)
{
*x = 0;
*y = 1;
return 0;
}
  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值