C语言中的作用域、链接属性与存储属性
C语言中的作用域、链接属性与存储属性
一、作用域(scope)
- 代码块作用域 - 表示{}之间的区域,下例所示,a可以在不同的代码块里面定义。 - #include<stdio.h> int main()
 {
 int f(int g){
 return g;
 } int a = 0;
 {
 int a = 2;
 printf("inner: %d\n", a);
 }
 printf("outter: %d\n", a);
 printf("inline function:%d\n", f(10));
 }
 - $ ./a.out
 inner: 2
 outter: 0
 inline function:10
 
C语言居然支持了内部函数,好神奇。
```c
//error: ‘i’ redeclared as different kind of symbol
int fun(int i)
{
    int i = 0;
    return i;
}
```
ANSI C中,形参的作用域为函数最外层的那个作用域,不能在函数体内声明同名的变量(K&R C可以,屏蔽形参)。
- 文件作用域 - 任何在所有代码块之外声明的标识符都具有文件作用域(file scope)。并且,通过#include指令包含到其他文件中的声明就好像它们是直接写在那些文件中一样。它们的作用域并不局限于头文件的文件尾。 
- 原型作用域 - int fun(int a);
 - 原型作用域(prototype scope)只适用于在函数原型中声明的参数名,将它独立出来只是为了这个名字不能与其他作用域的符号混淆,它其实没有什么用得,甚至都可以不写。事实上,唯一可能出现的冲突就是在同一个原型中不止一次使用同一个名字。 
- 函数作用域 - 它只适用于语句标签,用于goto语句。《C和指针》的作者说愿你永远不需要这方面的知识,哈哈!!! 
二、链接属性
当组成一个程序的各个源文件分别被编译之后,所有的目标文件以及那些从一个或多个函数库中引用的函数链接在一起,形成可执行文件。问题是,如果相同的标识符出现在几个不同的源文件中时该怎么办?标识符的链接属性决定如何处理在不同文件中出现的标识符。标识符的作用域与它的链接属性有关,但这两者并不相同。
链接属性一共有3种:
- none(无) - 总是被当做单独的个体,也就是说该标识符的多个声明被当作独立不同的实体。 
- internal(内部) - 在同一个源文件中的所有声明中都指向同一个实体,但位于不同源文件的多个声明则分属不同的实体。 
- external(外部): - 不论声明多少次、位于几个源文件都表示同一个实体。 - extern和static两个关键字可以用于设定标识符的链接属性。当没有这两个关键字时,默认的链接属性与标识符的作用域相关。 - typedef char *a;
 int b;
 int c(int d)
 {
 int e;
 int f(int g);
 ...
 }
 - 上面的代码块中,b、c、f有external链接属性,f在本代码中被调用,定义在其他源文件或者库中,所以也是external属性。其他的标识符都是none属性。 - static关键字可以把一个默认为external属性的标识符改为internal,如上例中,可以把b、c的链接属性改为internal,使其在其他源文件中不可见。 - static int b;
 static int c(int d);
 - extern 关键中可以把none属性改为external属性。 - // linkage_test1.c
 #include<stdio.h> extern int a; // 可选,因为默认就是external
 // 但是应该写上,增加程序可读性 int main() {
 printf("a = %d\n", a);
 extern int b; // 必需,默认为none
 printf("b = %d\n", b);
 }
 - // linkage_test1.c
 int a = 1;
 int b = 2;- 最后,当extern关键字用于源文件中一个标识符的一次声明时,它指定该标识符具有external链接属性,但是,如果它用于该标识符的第2次或者以后的声明时,它并不会更改由第一次声明所指定的链接属性。如下例所示: - static int i;
 int func()
 {
 extern int i; //i的链接属性仍然为static
 }
 
三、存储类型
变量的存储类型是指存储变量值的内存类型。变量的存储类型决定变量何时创建、何时销毁以及它的值将保持多久。有三个地方可以用于存储变量:普通内存、运行时堆栈、硬件寄存器。在这三个地方存储的变量具有不同的特性。
- 普通内存变量 - 变量的缺省存储类型取决于它声明的位置(作用域),凡是在任何代码块之外声明的变量总是存储与静态内存中,也就是不属于堆栈的内存,这类变量成为静态变量(static),可以通过static关键字将一个代码块内部变量由堆栈类型变为静态类型。静态类型的标识符存在ELF文件的.data(已初始化)或者.bss段(未初始化,默认值为0)。这些变量在程序未运行之前(通过内存加载)已经存在。 
- 堆栈变量 - 在代码块内部声明的变量的默认存储类型是自动的(automatic),可以使用关键字auto指定,但它极少使用,因为完全没必要。这些自动变量存在堆栈中。 
- 硬件寄存器变量 - 你可以通过关键字register来指定,提示程序运行时用硬件寄存器来存储该变量,但是编译器可以不鸟你,因为它认为它比你更清楚那个变量该用寄存器那个该用堆栈。 
变量的初始化
静态变量只能用常数进行初始化(其他静态变量都不行),如果未显性初始化,则默认值为0;
堆栈变量可以通过任何合法表达式初始化,因为它是在运行时创建,如果不初始化,其默认值为垃圾。
引用
--C和指针/ (美)里科(Reek, K. A.)著;徐波译. —北京:人民邮电出版社,2008. 4(2016. 5重印)
C语言中的作用域、链接属性与存储属性的更多相关文章
- C语言中的作用域,链接属性和存储类型
		作用域 当变量在程序的某个部分被声明的时候,他只有在程序的一定渔区才能被访问,编译器可以确认4种不同类型的作用域:文件作用域,函数作用域,代码块作用域和原型作用域 1.代码块作用域:位于一对花括号之间 ... 
- C/C++语言中变量作用域:局部变量,全局变量,文件级变量
		C/C++语言中的变量分为全局变量和局部变量. 这样的划分方式的根据是变量的可见范围或者叫做作用域. 1 局部变量 局部变量指的是定义在{}中的变量,其作用域也在这个范围内.尽管常见的局部变量都是定义 ... 
- c语言中变量和函数作用域深究
		首先,函数的作用域和访问权限基本可以参考 C语言中的作用域,链接属性和存储类型 也存在例外情况,比如内联函数 static inline,使用static 修饰 inline之后外部文件也可以访问内联 ... 
- C语言 变量的作用域和生命周期(转)
		转自 https://blog.csdn.net/u011616739/article/details/62052179 a.普通局部变量 属于某个{},在{}外部不能使用此变量,在{}内部是可以使用 ... 
- 详解Go语言中的屏蔽现象
		在刚开始学习Go语言的过程中,难免会遇到一些问题,尤其是从其他语言转向Go开发的人员,面对语法及其内部实现的差异,在使用Go开发时也避免不了会踩"坑".本文主要针对Go设计中的屏蔽 ... 
- ruby中的作用域
		作用域(scope)指的是变量的可达性或可见性.不同类型的变量有不同的作用域规则.与self类似,作用域在程序的执行过程中也在不断的变化,也可以根据上下文推断出"谁在什么作用域中" ... 
- C语言中的传值调用
		在c语言中每个变量都有两个属性一个是值,一个是址. 比方: int a = 2; 变量a的值是2,变量a的地址,能够用&取地址操作符获取,即&a. 因此以C语言的函数传递中具备两种方式 ... 
- Swift编程语言学习9—— 存储属性和计算属性
		属性将值跟特定的类.结构或枚举关联.存储属性存储常量或变量作为实例的一部分,计算属性计算(而不是存储)一个值.计算属性能够用于类.结构体和枚举里,存储属性仅仅能用于类和结构体. 存储属性和计算属性通经 ... 
- 《从零开始学Swift》学习笔记(Day 31)——存储属性
		原创文章,欢迎转载.转载请注明:关东升的博客 Swift中的属性分为存储属性和计算属性,存储属性就是Objective-C中的数据成员,计算属性不存储数据,但可以通过计算其他属性返回数据. 存储属性可 ... 
随机推荐
- DOM基础知识(概念、节点树、事件、Document)
			1. DOM概念 全称为 Document Object Model,译为文档对象模型 D:文档 - DOM将HTML页面解析为一个文档 —> document对象 O:对象 - DOM将H ... 
- dedecms清空栏目后,新建ID不从1开始的解决方法
			在后台SQL运行器运行下面的语句,这样新建的栏目ID就从1开始了: ALTER TABLE `dede_arctype` AUTO_INCREMENT =1; (注意表名) 下面是文章的,运行后,发布 ... 
- uva 11624  Fire! 【 BFS 】
			按白书上说的,先用一次bfs,求出每个点起火的时间 再bfs一次求出是否能够走出迷宫 #include<cstdio> #include<cstring> #include&l ... 
- php方法-------将汉字转为拼音或者提取汉字首字母
			将汉字转为全拼,提取汉字首字母 <?php /** * 基于PHP语言的汉语转拼音的类 * 兼容 UTF8.GBK.GB2312 编码,无须特殊处理 * 对中文默认返回拼音首字母缩写,其它字符不 ... 
- ZBrush中如何反选遮罩
			通过对ZBrush的学习,我们知道了如何手动创建遮罩,手动创建遮罩相对来说是最简单有效的方法,在某些特定的使用场合会起到事半功倍的效果.创建遮罩我们可以结合Ctrl键在物体保持编辑的状态下来执行,您可 ... 
- ZBrush中Mrgb、Rgb和M的使用
			ZBrush®软件工具架中所有的命令选项都是我们平时较为常用的,位于工具架的中间位置,有一个Mrgb.Rgb和M选项它们所表示的是材质及颜色,那么,在Zbrush中只要选择相应的选项,就可以同时绘制材 ... 
- background--详解(背景图片根据屏幕的自适应)
			background:有以下几种属性: background-color background-position background-size background-repeat backgroun ... 
- Day 05 流程控制
			流程控制 if 判断 语法: if if...else if...elif...else if判断是干什么的呢?if判断其实是在模拟人做判断.就是说如果这样干什么,如果那样干什么. if...else ... 
- 使用 Jersey 和 Apache Tomcat 构建 RESTful Web 服务
			作者: Yi Ming Huang, 软件工程师, IBM Dong Fei Wu, 软件工程师, IBM Qing Guo, 软件工程师, IBM 出处: http://www.ibm.com/de ... 
- Mysql干货收集
			mysql优化:https://www.cnblogs.com/duanxz/tag/mysql/default.html?page=1 
