《C Prime Plus》读书笔记(12):标识符的作用域,链接,存储

本文详细介绍了C语言中标识符的作用域,包括块作用域、函数作用域、文件作用域,以及链接的概念,如外部链接和内部链接。同时,讨论了标识符的存储期,如静态存储期、自动存储期、线程存储期和动态分配存储期,并解释了malloc()和free()的使用。此外,还阐述了不同类型的存储方案,如自动存储、寄存器存储、静态存储等,以及extern关键字的用途。
摘要由CSDN通过智能技术生成

1. 标识符的作用范围

1.1 程序在编译时的结构

在这里插入图片描述
翻译单元:源代码文件.c+其所有头文件.h


1.2 作用域

不细讲

  • 块作用域
  • 函数作用域
  • 函数原型作用域
  • 文件作用域 (文件作用域变量可以是下文中的外部链接或内部链接)

1.3 链接

  • 外部链接变量可在整个程序(所有源代码文件)使用
  • 内部链接变量可在整个翻译单元中使用
  • 无链接变量可在翻译单元中某一区域(作用域)使用(块作用域变量,函数作用域变量,函数原型作用域变量)

术语:
内部链接的文件作用域 — 简称为“文件作用域”
外部链接的文件作用域 — 简称为“全局作用域”、“程序作用域”

示例:

int glogal = 1; // 外部链接(全局作用域)
static int file = 2;  // 内部链接(文件作用域)

int main{return 0;}

2. 标识符的生存期

标识符的四大存储期:

  • 静态存储期
  • 自动存储期
  • 线程存储期
  • 动态分配存储期

2.1 ▲静态存储期

具有静态存储期的变量在程序执行期间将会一直存在

所有的文件作用域变量(内部链接和外部链接)都具有静态存储期

注意:

  • 对于块作用域变量,static 是表明其存储期,而非链接属性(仍未无链接变量)
  • 对于文件作用域变量,内部链接变量的static 是表明其链接属性,而非存储期
    //只不过static声明出来的内部链接变量是文件作用域变量,故自动具备了静态存储期

2.2 ▲自动存储期

自动存储期一般出现在块作用域中,程序进入块时,为具有自动存储期的变量分配内存,在程序推出块时,自动释放为其分配的内存

2.3 线程存储期

线程存储期用于并发程序设计中,具有线程存储期的变量,从声明到线程结束前一直存在。

2.4 动态分配存储期(malloc()与free())

使用malloc动态创建的变量,从malloc创建后到free释放前一直存在

//malloc与free
#include<stdio.h>

int main(){
	double * ptr;
	ptr = (double *) malloc(30 * sizeof(double));
	
	free(ptr);
	
	return 0;
}

malloc()参数为需要分配空间的字节数,free()参数为malloc返回的指针

malloc返回动态分配内存块的首字节地址,因此要通过一个指针来接收这个地址,分配空间失败时返回NULL空指针
为了提高程序的可读性,我们常常会使用类型转换,将malloc返回的地址转换为匹配的指针类型

free()函数只能够释放malloc()动态分配的空间,其他方式(如声明一个数组)分配的空间无法释放



3. 标识符的储存

因为标识符的储存方案由标识符的存储期和链接(作用域)决定,所以确定了存储方式也就确定了这个变量本身(我们一般根据变量的存储方式来命名变量)

五个常见储存方案

  • 自动存储 - 自动变量
  • 寄存器存储 - 寄存器变量
  • 静态无链接存储 - 块作用域的静态变量
  • 静态外部链接存储 - 外部链接的静态变量
  • 静态内部链接存储 - 内部链接的静态变量
存储类别存储期作用域链接声明方式
自动自动无链接块内声明
寄存器自动无链接块内声明,使用关键字register
静态无链接静态无链接块内声明,使用关键字static
静态内部链接静态文件内部链接所有函数外,且有关键字static
静态外部链接静态文件外部链接所有函数外

3.1 自动存储 - 自动变量

自动变量是声明在块中,在块作用域上,无链接,具有自动存储期的变量

为了强调变量该变量自动存储的类别,可以显示地使用关键字auto,确保变量为自动变量(确保自动存储类别)

自动变量不会自动初始化,只能显示地初始化(而静态变量自动初始化为0)

3.2 寄存器存储 - 寄存器变量

寄存器变量是通过register声明在块中,在块作用域上,无链接,具有自动存储期的变量

与普通的自动变量相比,一般来说 寄存器不储存在内存中而是直接储存在CPU的寄存器中(“编译器不一定允许储存”),因此访问和处理寄存器变量的速度更快。且因为是储存在寄存器上,故无法获得寄存器的储存地址,不允许指针操作


3.3 静态无链接存储 - 块作用域的静态变量

块作用域的静态变量是通过使用关键字static声明在块中,在块作用域上,无链接,具有静态存储期的变量

与普通的自动变量相比,块作用域的静态变量在所在函数块调用结束后并不会释放内存,而是一直保留在内存中,知道程序运行结束

代码示例:

// 块作用域的静态变量的特点
#include<stdio.h>

void Print(){
	int a = 0;
	static int b = 0;
	printf("局部变量a: %d, 块作用域的静态变量b:  %d\n", a, b);
}

int main(){
	for(int i = 0; i < 3; i++) Print();
	return 0;
}

在这里插入图片描述

3.4 静态内部链接存储 - 内部链接的静态变量

内部链接的静态变量是通过关键字static声明在所有函数外,在文件作用域上,内部链接,具有静态存储期的变量


3.5 静态外部链接存储 - 外部链接的静态变量

外部链接的静态变量是声明在所有函数外,在文件作用域上,外部链接,具有静态存储期的变量


4. extern的使用

extern"外部",意为 所声明变量的定义在外部,在别处

4.1 作用一:防止编译器混淆同文件中的声明与定义

在使用外部链接和内部链接的静态变量时,为了防止同名变量的覆盖(防止编译器混淆声明与定义),我们按声明的位置把变量分为:

  • 外部变量(external variable):,把变量的定义性声明放在了所有函数外面的变量
  • 内部变量:自动变量,寄存器变量,静态变量
#include<stdio.h>
int num = 1;  // 外部链接的静态变量
static char ch = 'a'; // 内部链接的静态变量
int main(){
	 extern int num; // 该语句为声明而非定义(再次声明了num外部链接的静态变量)
	 extern char ch;
  /* int num;          该语句为定义,而非声明(定义了一个同名为num的局部变量) */
  /* char ch;          该语句为定义,而非声明(定义了一个同名为ch的局部变量) */

	return 0;
}

4.2 作用二:防止编译器混淆不同文件中声明与定义

#incldue<stdio.h>
int num1 = 1;  // 此处定义了该文件中的一个外部链接的静态变量num1
extern int num2;  // 此处是声明了一其他文件中的一个外部链接的静态变量num2

int main(){

	return 0;
}

总结:
函数内使用extern,那么“外部”是相对于函数的,也就是指该文件的函数外
函数外使用extern,那么“外部”是相对于文件的,也就是指该文件外


在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值