您的位置:首页 > 编程语言 > C语言/C++

C语言中的auto,register,volatile,extern,static,const

2013-10-29 23:30 513 查看
你能很随意地说出C语言中 auto,register,volatile,extern,static,const这几个关键字的含义和用法么?

auto
这个关键字用于声明变量的生存期为自动。

C程序是面向过程的,在C代码中会出现大量的函数模块,每个函数都有其生命周期(也称作用域),在函数生命周期中声明的变量通常叫做局部变量,也叫自动变量。

auto 变量是用堆栈(stack)方式占用储存器空间,因此,当执行此区段是,系统会立即为这个变量分配存储器空间,而程序执行完后,这个堆栈立即被系统收回.在大括号{}内声明.这个关键字不怎么多写,因为所有的变量默认就是auto的。

例子

#include <stdio.h> void sayHi();  int main() { 	printf("Hello!\n"); 	sayHi(); 	return 1; }  void sayHi() { 	//int age = 20; 	auto age = 20; 	printf("I'm %d.\n",age); }

运行结果:



register

这个关键字命令编译器尽可能的将变量存在CPU内部寄存器中而不是通过内存寻址访问以提高效率.但也只是尽可能,因为cpu就那几个寄存器,不能全给你用了。

限制:必须是能被cpu寄存器所能接受的类型,必须为单个的值,并且长度应小于或者等于整型的长度,而且registor变量可能不存放在内存中,所以不能用取地址运算符来获取地址。
例子:(算Pi)

#include <stdio.h> #include "stdlib.h" #include <time.h>     #include <sys/time.h>  #define SCALE 10000 #define ARRINIT 2000 //int pow(int num, int n); int main() { 	struct timeval tpstart,tpend;       int timeuse;     gettimeofday(&tpstart,NULL);       	pi_digits(100000); 	 	gettimeofday(&tpend,NULL);   	 	timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;   	 	printf("\nDone in %d ms.\n",timeuse); 	return 1; }  void pi_digits(int digits) {     int carry = 0;     int arr[digits + 1];     int i,j;     for (i = 0; i <= digits; ++i)         arr[i] = ARRINIT;     for (i = digits; i > 0; i-= 14) 	{ 		//int sum = 0;         register int sum = 0;        	for (j = i; j > 0; --j)         	{            	sum = sum * j + SCALE * arr[j];            	arr[j] = sum % (j * 2 - 1);        		sum /= j * 2 - 1;        	}         printf("%04d", carry + sum / SCALE);         carry = sum % SCALE;     } }

在不生命register变量的情况下,运行时间是:



将pi_digits函数中的sum声明为register之后,运行结果:



运行时间有明显的减少。

volatile
在本次线程内, 当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存器中取值;当变量值在本线程里改变时,会同时把变量的新值copy到该寄存器中,以便保持一致。
当变量在因别的线程等而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致。
当该寄存器在因别的线程等而改变了值,原变量的值不会改变,从而造成应用程序读取的值和实际的变量值不一致。
volatile应该解释为“直接存取原始内存地址”比较合适,“易变的”这种解释简直有点误导人。

这个在多线程编程中常常会用到。
深究的话可以扯到编译原理里面去了。
例子:

#include <stdio.h>  int main()  {  	//Has bug when not using volatile 	//int result = 0; 	volatile int result = 0; 	int a = result; 	printf("result = %d\n",a); 	int input = 1;   	__asm__ __volatile__ ("addl %2,%0":"=r"(result):"r"(result),"r"(input));   	int c = result;   	printf("result = %d\n",c);     return 1; }




使用汇编的目的是骗过编译器改变寄存器中变量的值。
在没有使用volitile的情况下:
第一个用的是-g参数,没有使用编译器的优化,所以结果是正确的。
第二个使用的是-O2参数,等于是编译release版本,gcc对代码进行了优化,比如常量传播,再次运行,结果并不正确。

接下来使用volitile关键字,结果正确。
尼玛,汇编是硬伤。
注意:频繁地使用volatile很可能会增加代码尺寸和降低性能,因此要合理的使用volatile。

extern

意为“外来的”···它的作用在于告诉编译器:有这个变量,它可能不存在当前的文件中,但它肯定要存在于工程中的某一个源文件中。

最常用的状态是多个文件的工程的时候,调用另外文件的共有变量和函数。
例子:
a.c

#include <stdio.h>  int a = 20; int fun(int n)  {  	int sum = 0; 	while(n>1) 	{ 		sum += n--; 	} 	return sum; }


main.c
#include <stdio.h>  extern int a; extern int fun(int n); int main()  {  	printf("fun: %d\n",fun(a)); 	return 1; }




static
c语言中的static和extern是相对的。
static也可以用来休息变量和函数。
在修饰变量的时候,可以是:
全局变量,作用域仅限于变量被定义的文件中,其他文件即使使用extern声明也没办法使用他。
局部变量,只能在函数中使用,同一个文档中的其他函数也用不了。由于static修饰的变量存放在内存的静态区,所以即使这个函数运行结束,这个静态变量的值也不会销毁,下次仍然使用内存中的这个值。
在修饰函数的时候,
函数的作用域仅局限于本文件,也就是内部函数,好处:不同的人编写不同的函数时,不用担心自己定义的函数是否会与其他文件中的函数重名。
例子:函数使用计数器

#include <stdio.h>  void count(); int main() { 	int i; 	for (i = 1; i <= 3; i++) 		count(); 	return 0; }  void count() {  	static num = 0;  	num++;  	printf("I have been called %d times.\n",num); }




const
const称之为常量修饰符,即就是说其所修饰的对象为常量。当你代码中想要设法阻止一个变量被改变,那么这个时候可以选择使用const关键字。在你给一个变量加上const修饰符的同时,通常需要对它进行初始化,在之后的程序中就不能再去改变它.

const修饰符的几个典型作用:

1. const类型定义:指明变量或对象的值是不能被更新,引入目的是为了取代预编译指令

2. 可以保护被修饰的东西,防止意外的修改,增强程序的健壮性;

3. 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。

4. 可以节省空间,避免不必要的内存分配。

使用const的直接的作用就是让更多的逻辑错误在编译期被发现。所以我们要尽可能的多使用const。

当const 和 指针斯混在一起的时候,就会很蛋疼。
在此对于判断const的修饰对象给出一种常使用的方法,我们以*为界线,如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量。

比如:
const int *p;
int const *q;

int * const r= &n;

p和q都是一样,两个指针,指向的变量为常量,r本身是一个常量,不能再指向其他位置。

参考
语言中auto,register,static,const,volatile,extern的区别 - http://blog.csdn.net/sdwuyulunbi/article/details/8469058
C语言变量存储类型auto static extern static extern register - http://7008965.blog.51cto.com/6998965/1179780
C语言的那些小秘密 - http://blog.csdn.net/bigloomy/article/details/6595197

《C语言深度剖析》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐