C中的auto、static、register、extern、const和volitate

C语言中的每一个变量和函数有两个属性:数据类型和数据的存储类别。

数据类型(整形、字符型等),

存储类别是指数据在内存中存储的方法,存储方法有两大类:静态存储类和动态存储类。具体包括四种:自动的(auto),静态的(static),寄存器的(register)和外部的(extern)。

auto变量:函数中的局部变量,如不专门声明static,一般都是动态地分配存储空间。自动变量:在调用该函数时系统会给他们分配存储空间,一旦函数调用结束这些存储空间就会自动释放。关键字“auto”可以省略,不写则隐含确定为“自动存储类别”,属于动态存储方式。

static声明变量:用static声明的静态局部变量,在函数调用结束后不消失,反而保留当前的数据,在下一次该函数调用时,该变量现有的值就是上一次函数调用结束时的值。

一般用static声明一个变量的作用有二:(1)对局部变量用static声明,则为该变量分配的空间在整个程序执行期间始终存在。(2)对全部变量用static声明,则该变量的作用域只限于本文件模块,即被声明的文件中。

 1 f(int a)
 2 
 3 {
 4 
 5     auto b=0; //将b定义为auto类型。
 6 
 7     static c=3; //将c定义为static类型。
 8 
 9     b=b+1,c=c+1;
10 
11     return(a+b+c);
12 
13 }
14 
15 main()
16 
17 {
18 
19     int a=2,i;
20 
21     for(i=0;i<3;i++)
22 
23     printf("%d",f(a));
24 
25 }

在第一次调用f函数时b=0,c=3,第一次调用结束后b=1,c=4,a+b+c=7;执行完之后由于c是静态局部变量,在函数调用结束后,它并不释放,所以保留c=4。而b还是0。所以程序输出7,8,9。

static还可以声明函数,eg:static int fun(int a, int b)称fun为内部函数,或者静态函数。内部函数的使用只限于所在文件,而且不同文件中的同名内部函数互不干扰。

register变量:一般变量的值都是存储在内存中,(当程序需要用到哪一个变量的值,由控制器发出指令将内存中该变量的值送到运算器,完了如果需要存数,再从运算器将数据送到内存中存放。)所以就引出一个问题,如果我们进行一段频繁的运算,则存储变量的值肯定要花费不少时间,所以C语言允许将局部变量的值存放在寄存器中,这样需要时就直接搬用,不必再进行过内存。提高运算速度。

extern声明外部变量:外部变量(即全局变量)是在函数的外部定义的。作用域为从变量的定义处开始,到本程序文件的结尾。可以在一个文件内声明外部变量,如:

{

main()

{

extern A,B;

printf("%d",max(A,B));

} int A=13,B=-8;

也可以在多文件的程序中声明外部变量。

extern还可声明函数,eg:extern int fun(int a, int b);声明的外部函数可供其他文件调用,在C中,定义函数时省略extern,则隐含为外部函数。

别人问起,不能简单说const表示常数,这样会让别人觉得很外行。或许可以说是只读,其实也不完全正确。务必要弄清楚一下几个定义的含义:

const int a; //a是一个常整型数

int const a; //a是一个整型常数

const int *a; //a是一个指向常整型数的指针,从这里可以看出整型数不可以修改,但指针可以。

int * const a; //a是一个指向整型数的常指针,整型数可以修改,指针不能修改。

int const * a const; //a是一个指向常整型数的常指针。

如果能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由:

1).关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。)

2). 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。

3). 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。

关键字volatile有什么含意 并给出三个不同的例子。

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:

1). 并行设备的硬件寄存器(如:状态寄存器);

2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables);

3). 多线程应用中被几个任务共享的变量;

回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。

假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。

1). 一个参数既可以是const还可以是volatile吗?解释为什么。

2). 一个指针可以是volatile 吗?解释为什么。

3). 下面的函数有什么错误:

int square(volatile int *ptr)

{

return *ptr * *ptr;

}

下面是答案:

1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。

2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时

3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:

int square(volatile int *ptr)

{

int a,b;

a = *ptr;

b = *ptr;

return a * b;

}

由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:

long square(volatile int *ptr)

{

int a;

a = *ptr;

return a * a;

}

猜你喜欢

转载自www.cnblogs.com/liangbo-1024/p/9263445.html