存储类(作用域、链接、存储时期)

关键字:

  auto、extern、static、register、const、volatile、restricted、

函数:

  rand()、srand()、time()、malloc()、calloc()、free()、

 

不同的存储类提供了变量的作用域(scope)、链接(linkage)以及存储时期(storage duration)的不同组合

变量的作用域和链接一起表明程序的哪些部分可以通过变量名来使用该变量

 

作用域:一个C变量的作用域可以是代码块作用域、函数原型作用域、或者文件作用域。

函数原型作用域是从变量定义处一直到原型声明的末尾。参数名称通常是无关紧要的,编译器所关心的只是参数的类型。

名字起作用的一种情形是变长数组参量:
  void use_a_VLA (int m, int n, int arr[m][n]);

 

链接:一个C变量具有下列链接之一:外部链接(external linkage)、内部链接(internal linkage)、空链接(no linkage)

具有代码块作用域或者函数原型作用域的变量有空链接,意味着它们是由其定义所在的代码块或函数原型所私有的。具有文件作用域的变量可能有内部或者外部链接。一个具有外部链接的变量可以在一个多文件程序的任何地方使用。一个具有内部链接的变量可以在一个文件的任何地方使用

int giants = 5;        // 文件作用域, 外部链接

static int dodgers = 3;    // 文件作用域, 内部链接

 

存储时期: 一个C变量有以下两种存储时期之一,静态存储时期(static storage duration)和自动存储时期(automatic storage duration)。一个C变量具有静态存储时期,它在程序执行期间将一直存在。具有文件作用域的变量具有静态存储时期。

具有文件作用域的变量具有静态存储时期。注意对于具有文件作用域的变量,关键词static表明链接类型,并非存储时期。一个使用static

声明了的文件作用域变量具有内部链接,而所有的文件作用域变量,无论它具有内部链接,还是具有外部链接,都具有静态存储时期

 

 

int main (void)

{

  auto int plox;   // 自动存储类,可以省去auto(自动存储期、代码块作用域、空链接)

}

 

寄存器变量:通常,变量存储在计算机内存中。如果幸运,寄存器变量可以被存储在CPU寄存器中,或更一般地,存储在速度最快的可用内存中,从而可以比普通变量更快的被访问和操作。因为寄存器变量多是存放在一个寄存器而非内存中,所以无法获得寄存器变量的地址。但在其他的许多方面,寄存器变量与自动变量是一样的。也就是说,它们都有代码块作用域、空链接以及自动存储时期。通过存储类说明符register可以声明寄存器变量

   我们说"如果幸运"是因为声明一个寄存器类变量仅是一个请求,而非一条直接的命令。编译器必须在您的请求与可用寄存器的个数或可用高速内存的数量之间做权衡,所以您可能达成不了自己的愿望。这种情况下,变量称为一个普通的自动变量;然而,您依然不能对它使用地址运算符。

  可以把一个形式参量请求为寄存器变量。只需在函数头部使用register关键字

  void macho (register int n);

  可以使用register声明的类型是有限的。例如,处理器可能没有足够大的寄存器来容纳double类型。

 

具有代码块作用域的静态变量:    静态变量(static variable)这一名称听起来很矛盾,像是一个不可变的变量。实际上,“静态”是指变量的位置固定不动。具有文件作用域的变量自动(也是必须的)具有静态存储时期。也可以创建具有代码块作用域,兼具静态存储的局部变量。这些变量和自动变量具有相同的作用域,但当包含这些变量的函数完成工作时,它们并不消失。也就是说,这些变量具有代码块作用域、空链接,却有静态存储时期。这样的变量通过使用存储类说明符static(这提供了静态存储时期)在代码块内声明(这提供了代码块作用域和空链接)创建。

  void trystat (void)

  {

    int fade = 1;

    static int stay = 1;

  }

   具有代码块作用域的静态变量只在编译时被初始化一次。如果不显示的对静态变量进行初始化,它们将被初始化为0。

  第一个语句确实是函数trystat函数的一部分,每次调用该函数时都会执行它。它是个运行时的动作。而第二个语句实际上并不是函数trystat函数的一部分。如果用调试程序逐步运行该程序,您会发现程序看起来跳过了那一步。那是因为静态变量和外部变量在程序调入内存时已经就位了。把这个语句放在trystat函数中是为了告诉编译器只有函数trystat可以看到该变量。它不是运行时执行的语句。

  对函数形式参量不能使用static

 

  静态存储期变量初始化只能使用常量表达式初始化,不能使用变量表达式(或者不初始化,则编译器自动初始化为0)

 

  C语言中有5个存储类说明符的关键字,它们是auto、register、static、extern 以及typedef。关键字typedef与内存存储无关,由于语法原因被归入此类。特别地,不可以在一个声明中使用一个以上存储类说明符,这意味着不能将其他任一存储类说明符作为typedef的一部分。

 

 

函数calloc()还有一个特性,他将块中的全部位都置为0(然而要注意,在某些硬件系统中,浮点值0不是用全部位为0来表示的)。

 
类型限定词: 不变性(const)、易变性(volatile),  restrict(c99,方便编译器优化)

volatile告诉编译器该变量除了可被程序改变以外还可被其他代理改变。典型地,它被用于硬件地址和与其他并行运行的程序共享的数据。例如,一个地址中可能保存着当前的时钟时间。不管程序做些什么,该地址的值都会随着时间改变。另一种情况是一个地址被用来接收来自其他计算机的信息。

语法同const:

  volatile int loc;  /* loc是一个易变的值*/

  volatile int * ploc;   /* ploc指向一个易变的值*/

 

关键字restrict通过允许编译器优化某几种代码增强了计算支持。它只可用于指针,并标明指针是访问一个数据对象的唯一且初始的方式。为了清除为何这样做有用,我们需要看一些例子。考虑下面的例子:

  int ar[10];

  int * restrict restar = (int *)malloc (10 * sizeof(int));

  int * par = ar;

  这里,指针restar是访问由malloc()分配的内存的唯一且初始的方式。因此,他可以由关键字restrict限定。然而,par指针既不是初始的,也不是访问数组ar中数据的唯一方式,因此不可以把他限定为restrict。

posted @ 2014-09-04 15:20  挨踢淫才  阅读(433)  评论(0编辑  收藏  举报