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

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

2013-10-29 23:30 579 查看
你能很随意地说出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语言深度剖析》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐