当前位置:嗨网首页>书籍在线阅读

02-存储类别

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

12.1 存储类别

C提供了多种不同的模型或存储类别(storage class)在内存中存储数据。要理解这些存储类别,先要复习一些概念和术语。

本书目前所有编程示例中使用的数据都存储在内存中。从硬件方面来看,被存储的每个值都占用一定的物理内存,C语言把这样的一块内存称为对象(object)。对象可以存储一个或多个值。一个对象可能并未存储实际的值,但是它在存储适当的值时一定具有相应的大小(面向对象编程中的对象指的是类对象,其定义包括数据和允许对数据进行的操作,C不是面向对象编程语言)。

从软件方面来看,程序需要一种方法访问对象。这可以通过声明变量来完成:

int entity = 3;

该声明创建了一个名为 entity 的标识符(identifier)。标识符是一个名称,在这种情况下,标识符可以用来指定(designate)特定对象的内容。标识符遵循变量的命名规则(第2章介绍过)。在该例中,标识符 entity 即是软件(即C程序)指定硬件内存中的对象的方式。该声明还提供了存储在对象中的值。

变量名不是指定对象的唯一途径。考虑下面的声明:

int * pt = &entity;
int ranks[10];

第1行声明中, pt 是一个标识符,它指定了一个存储地址的对象。但是,表达式 pt 不是标识符,因为它不是一个名称。然而,它确实指定了一个对象,在这种情况下,它与 entity 指定的对象相同。一般而言,那些指定对象的表达式被称为左值(第5章介绍过)。所以, entity 既是标识符也是左值; pt 既是表达式也是左值。按照这个思路, ranks + 2 entity 既不是标识符(不是名称),也不是左值(它不指定内存位置上的内容)。但是表达式 (ranks + 2 * entity) 是一个左值,因为它的确指定了特定内存位置的值,即 ranks 数组的第7个元素。顺带一提, ranks 的声明创建了一个可容纳10个 int 类型元素的对象,该数组的每个元素也是一个对象。

所有这些示例中,如果可以使用左值改变对象中的值,该左值就是一个可修改的左值(modifiable lvalue)。现在,考虑下面的声明:

const char * pc = "Behold a string literal!";

程序根据该声明把相应的字符串字面量存储在内存中,内含这些字符值的字符串字面量就是一个对象。由于字符串字面量中的每个字符都能被单独访问,所以每个字符也是一个对象。该声明还创建了一个标识符为 pc 的对象,存储着字符串的地址。由于可以设置 pc 重新指向其他字符串,所以标识符 pc 是一个可修改的左值。 const 只能保证被 pc 指向的字符串内容不被修改,但是无法保证 pc 不指向别的字符串。由于 pc 指定了存储 'B' 字符的数据对象,所以 pc 是一个左值,但不是一个可修改的左值。与此类似,因为字符串字面量本身指定了存储字符串的对象,所以它也是一个左值,但不是可修改的左值。

可以用存储期(storage duration)描述对象,所谓存储期是指对象在内存中保留了多长时间。标识符用于访问对象,可以用作用域(scope)和链接(linkage)描述标识符,标识符的作用域和链接表明了程序的哪些部分可以使用它。不同的存储类别具有不同的存储期、作用域和链接。标识符可以在源代码的多文件中共享、可用于特定文件的任意函数中、可仅限于特定函数中使用,甚至只在函数中的某部分使用。对象可存在于程序的执行期,也可以仅存在于它所在函数的执行期。对于并发编程,对象可以在特定线程的执行期存在。可以通过函数调用的方式显式分配和释放内存。

我们先学习作用域、链接和存储期的含义,再介绍具体的存储类别。