12.1存储类别
-
作用域描述程序中可访问标识符的区域。一个C变量的作用域可为块作用域、函数作用域、函数原型作用域或文件作用域。块是用一对花括号括起来的代码区域。函数作用域仅用于goto语句的标签。函数原型作用域用于函数原型中的形参名,编译器再处理函数原型中的形参只关心它的类型,而形参名通产无关紧要,只有在变长数组中,形参名才有用。变量定义在函数外面,具有文件作用域,成为全局变量。
-
翻译单元和文件:通常在源代码中包含一个或多个头文件。头文件会依次包含其它头文件,所以会包含多个单独的物理文件。但是,C的预处理实际上是用包含的头文件内容替换#include指令。所以,编译器源代码文件和所有头文件看成是一个包含信息的单独文件。这个文件被称为翻译单元。描述一个具有文件作用域的全局变量时,它的实际可见单元是整个翻译单元。
-
链接:C变量有3种链接属性,外部链接、内部链接 或无链接。具有块作用域、函数作用域、函数原型作用域的变量都是无链接变量。具有文件作用域的变量具有内部链接或外部链接。C标准用“内部链接的文件作用域”描述仅限于一个翻译单元的作用域,用”外部链接的文件作用域“描述可延伸至其他翻译单元的作用域。
-
存储期:C对象有4种存储期-静态存储期、线程存储期、自动存储期、动态分配存储期。如果对象具有静态存储期,那么它在程序执行期间一直存在,所有文件作用域的变量都具有静态存储期。块作用的变量通常具有自动存储期。自动变量不会初始化,除非显式初始化它,否则为垃圾值(不是0)。寄存器变量和自动变量相似,但是访问和处理这些数据的速度更快,该变量的地址不能被获取。
-
如果内层块中声明的变量与外层块中的变量同名,内层块会隐藏外层快的定义。但是离开内层块后,外层块变量的作用域又回到了原来的作用域。
int giants=5; //文件作用域,外部链接
static int dodgers=3; //文件作用域,内部链接;
int tern=1; //定义式声明
int main()
{
extern int tern; //引用式声明
}
- 储存类别和函数:外部函数可以被其他文件的函数访问,但是静态函数只能用于其定义所在的文件。用extern关键字声明定义在其他文件中的函数。这样做是为了表明当前文件中使用的函数被定义在别处。除非使用static关键之,否则一般函数都默认为extern。
12.2随机函数和静态变量
static unsigned long int next=1;
unsigned int rand0(void)
{
/*伪随机数生成魔幻公式*/
next=next*1103515245+12345;
return (unsigned int) (next / 65536) % 32768;
}
- srand()函数可以重置种子
- 自动重置种子:如果C实现允许访问一些可变的量(如,时钟系统),可以用这些值初始化种子值。time()返回的值类型名是time_t,具体类型与系统有关。
srand((unsigned int)time(0)); //初始化种子
- 注意使用srand()和rand()函数,需要在头文件中包含stdlib.c头文件。
- 想获得一定范围内的随机数,需用求余操作。
- calloc()函数:
newmem = (long *)calloc(100, sizeof (long) );
第一个参数是所需的储存单元数量,第二个参数是储存单元的大小。 p2 = (int (*)[6]) malloc(n * 6 * sizeof(int) ); //n*6数组
- 程序把它可用的内存分为3个部分:一部分供具有外部链接、内部链接和无链接的静态变量使用;一部分供自动变脸使用;一部分供动态内存分配。静态存储类型所用的内存数量在编译时确定,只要程序还在运行,就可访问储存在该部分的数据。该类别的变量在程序开始执行时被创建,在程序结束时被销毁。自动存储类别的变量在程序进入变量定义所在块时存在,在程序离开块时消失。这部分的内存通常作为栈来处理。动态分配的内存在调用malloc()或相关函数时存在,在调用free()后释放。
- 在指针和形参中使用const,简而言之,const放在的左侧任意位置,限定了指针指向的数据不能改变;const放在的右侧,限定了指针本身不能改变。
- volatile():volatile是一个类型修饰符(type specifier).volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。
- restrict():C语言中的一种类型限定符(Type Qualifiers),用于告诉编译器,对象已经被指针所引用,不能通过除该指针外所有其他直接或间接的方式修改该对象的内容。
12.7本章小结
- 自动—在块中不带存储类别说明符或者带auto存储类别说明符声明的变量(或作为函数头中的形参)属于自动存储类别,具有自动存储期、块作用域、无链接。如果未初始化自动变量,它的值是未定义的。
- 寄存器—在块中带register存储类别说明符的变量属于寄存器存储类别,具有自动存储期、块作用域、无链接,且无法获取地址。把一个变量声明为寄存器变量即请求编译器将其存储到访问速度最快的区域。如果未初始化寄存器变量,它的值是未定义的。
- 静态、无链接—在块中带static存储类别说明符声明的变量属于“静态、无链接”存储类别,具有静态存储期、块作用域、无链接。只在编译时被初始化一次。如果未显式初始化,它的字节都被设置为0.
- 静态、外部链接—在所有函数外部且没有使用static存储类别说明符声明的变量属于“静态、外部链接”存储类别,具有静态存储期、文件作用域、外部链接。只在编译时被初始化一次。如果未显式初始化,它的字节都被设置为0.
- 静态、内部链接—在所有函数外部且使用了static存储类别说明符声明的变量属于“静态、内部链接”存储类别,具有静态存储期、文件作用域、内部链接。只在编译时被初始化一次。如果未显式初始化,它的字节都被设置为0.