变量属性与存储


主要学习变量的各种属性,以及加深了变量与存储的关系。真的不太熟悉的就是链接属性吧。(存储类名字不熟悉)


1.程序运行的基本概念:
1).存储类:
存储类就是存储类型,描述变量在哪里存放(堆,栈,代码段(.text),数据段(.data),bss段(ZI段)...),在哪里内存段中存储。
2).作用域:
描述一个变量起作用的范围,一般是是当前代码块/文件作用域(注意同名的全局变量和局部变量)
3).生命周期:
描述一个变量何时诞生(运行时分配空间给这个变量),何时消亡(运行时回收内存,以后不能访问这个地址或这个地址与变量无关)
4).链接属性:
源代码在编译成.o文件时,里面有符号和代码段、数据段、bss段等分段。符号是编程中的函数名,变量名;程序运行时能变量名,函数名能和内存联系起来,靠的就是符号
做链接。

链接时能把.o文件实际上就是把符号和相应的段链接起来。

C语言中的符号有三种链接属性:外连接属性、内链接属性、无连接属性。

2.linux下的内存映像:


1).代码段,只读数据段:
a.代码段对应程序中的代码(函数),在linux中又叫文本段(.text)
b.只读数据段保存那些程序运行期间不能被写的数据(部分平台下的const)

2).数据段,清零段(bss):
a.数据段存:显示初始化非零的全局变量;显式初始化为非0的static局部变量
b.bss段存:显式初始化为0或者未显式初始化的全局变量;显式初始化为0或未显式初始化的static局部变量

3).堆

4).文件映射区:
进程打开文件后,从硬盘把文件的内容读到文件映射区,之后在内存中操作这个文件,事后把文件映射区的内容写回硬盘。

5).栈:
存放局部变量,函数调用传参也会用到栈;(栈脏,注意栈里的变量要是没初始化值是不定的)

6).内核映射区:
(1)内核映射区就是将操作系统内核程序映射到这个区域了。
    (2)利用虚拟技术,每个进程都认为0xc0000000以上区域是内核空间,其以下是自己的活动空间。每个进程的独享空间不同,但是内核空间是唯一的。

补充:
1.C语言程序运行时环境有一定要求,单独个人写的C语言程序没法直接在内存中运行,需要外部一定的协助,这段协助的代码叫加载运行代码(或者叫构建C运行时环境的代码,这一段代码在操作系统下是别人写好的,会自动添加到我们写的程序上,这段代码的主要作用是:给全局变量赋值、清bss段。),要是没OS就要我们自己写加载运行代码咯。

2.数据段的全局变量或静态局部变量都是有非0的初值的,这些初值在main函数运行之前就已经被初始化了,是重定位期间完成的初始化。



3.存储类相关的关键字:
(1)auto:
只能修饰局部变量(自然定义在栈上),我们平时其实用的就是auto,不过是省略了;

(2)static:
1).修饰局部变量:静态局部变量和普通局部变量只要是存储类不同
2).修饰全局变量:静态全局变量和非静态全局变量主要是链接属性不同。
静态局部变量和全局变量异同:
同:存储类和生命周期
异:作用域:静态局部变量和非静态局部变量一样;
链接属性:静态局部变量是无连接,全局变量是外连接

(3)register
一般用来修饰全局变量,使其尽量放在寄存器中处理更快。(寄存器不够用就放不进去了)

(4)extern(C编译是以单个.c源文件为单位)
extern主要用来声明全局变量,使其可以跨文件使用。是在a.c中定义全局变量(int a=10;),而在b.c中使用该变量前需要声明它(extern int a;)。
将来在链接的时候链接器会在别的.o文件中找到这个同名变量。

(5)volatile:(英文意思:易变的,可变的)
用来修饰变量,表示这个变量可以被编译器以外的(编译器没有预料的情况,自然不是代码造成的)东西改变。
譬如在中断处理程序isr中更改了这个变量的值,譬如多线程中在别的线程更改了这个变量的值,譬如硬件自动更改了这个变量的值(一般这个变量是一个寄存器的值);
编译器在一般情况下会优化,帮助提高效率;但在以上三种情况下编译器优化是预料不到会产生什么结结果,为了避免出错,用volatile告诉编译器不用优化。
例子:
int a,b,c;
a=10;
b=a;
    c=b;  
正常情况下编译器会优化,只取一次值,写三次(三次都写10)这时若因为以上三种情况在2-3句a的值或者3-4句间b的值被改变,那么结果就错了。如果用
volatile int a,b,c;那么不优化取三次写三次就不会出错了。

(6)restrict:
1)c99中才支持的,所以很多延续c89的编译器是不支持restrict关键字,gcc支持的。
2)restrict只用来修饰指针,修饰普通变量就跟没用一样;restrict也是和编译器行为特征有关的(加上用来优化),加上这个说明指针指向的变量值只能用指针来改变;
参考:http://blog.chinaunix.net/uid-22197900-id-359209.html

(7)typedef
。。。


4.属性详解:
(1).作用域:
1).
局部变量代码块作用域:

a.一个局部变量可以被访问和使用的范围仅限于定义这个局部变量的代码块中定义式之后的部分

b.全局变量和函数的文件作用域:
函数和全局变量的作用域是定义所在的整个.c文件之内定义式之后的部分;(两个方法:在前面定义;在后面定义,前面声明)
c.在c89标准的编译器中(现在很多编译器还延续使用c89标准),所有的局部变量必须先定义在最前面,在变量定义之前不能有一句执行代码。在c99标准的编译器中(gcc兼容c99标准)可以允许在代码块内任意地方定义变量。但是允许定义的变量还是只能使用在定义了之后,定义之前还是不能用的。

2).同名变量掩蔽规则:
作用域不重叠,重名没关系;重叠了,在交叠范围内作用域小的那个会掩盖掉作用域大的。

(2).生命周期:
栈变量:
堆变量;
数据段,bss段:定义的全局变量直至程序终结,期间一直占着内存;局部static的生命周期和全局变量一样,作用域和非静态局部变量一样;
代码段,只读段;不关心


(3).链接属性:
1).编译是为了将函数/变量等变成.o二进制的机器码格式,链接是为了将各个独立分开的二进制的函数链接起来形成一个整体的二进制可执行程序

2).编译以文件为单位、链接以工程为单位
(1)编译器工作时是将所有源文件依次读进来,单个为单位进行编译的。
(2)链接的时候实际上是把第一步编译生成个单个的.o文件整体的输入,然后处理链接成一个可执行程序。
3).
外连接:外部链接属性,也就是说这家伙可以在整个程序范围内(言下之意就是可以跨文件)进行链接,譬如普通的函数和全局变量属于外连接。
内链接:(c文件内部)内部链接属性,也就是说这家伙可以在当前c文件内部范围内进行链接(言下之意就是不能在当前c文件外面的其他c文件中进行访问、链接)。static修饰的函数/全局变量属于内链接。

无连接:这个符号本身不参与链接,它跟链接没关系。所有的局部变量(auto的、static的)都是无连接的

4).static的第二种用法:修饰全局变量和函数(可以在一定程度上解决重名问题)
普通的(非静态)的函数/全局变量,默认的链接属性是外部的
static(静态)的函数/全局变量,链接属性是内部链接。


变量属性与存储_第1张图片

你可能感兴趣的:(C语言若干问题,局部变量,全局变量,存储,数据,c语言)