一、C程序存储空间布局

C程序的部分组成:

      1)正文段——CPU执行的机器指令部分;一个程序只有一个副本;只读,防止程序由于意外事故而修改自身指令;
      2)初始化数据段(数据段)——在程序中所有赋了初值的全局变量存放在这里。
      3)非初始化数据段(bss段)——在程序中没有初始化的全局变量;内核将此段初始化为0。
      4)栈——增长方向:自顶向下增长;自动变量
以及每次函数调用时所需要保存的信息(返回地址;环境信息)。
      5)堆——动态存储分。

|-----------|
|                |
|-----------|
|    栈         |  
|-----------|
|-----------|
|    堆         |
|-----------|
| 未初始化  |
|-----------|
|   初始化   |
|-----------|
|  正文段    |
|-----------|

二、 面向过程程序设计中的static

1、全局变量

作用: 改变变量的作用域
内存:不变,全局变量本来就是存放在静态存储区(初始化数据段或非初始化数据段)
初始化:未经初始化的全局静态变量将被自动初始化为0(内核 or 编译器来做?)
作用域:限定作用域为文件内从定义之处开始到文件结尾 (非静态全局变量在整个源程序内有效)。

C语言中这样做有两个好处:
1)不会被其他文件所访问,修改
2)其他文件中可以使用相同名字的变量,不用担心命名冲突
在C++中,这种方法将逐步被命名空间取代。

 //定义全局静态变量,自动初始化为0,仅在本文件中可见
static int num = 0;

2、局部静态变量:

作用: 改变存储方式(同时也改变了生存期,与该特性相对的是auto, register)
内存:静态存储区
初始化: static局部变量在所处模块在初次运行时进行初始化工作, 且只操作一次
作用域:不变
/3、静态函数:在函数的返回类型前加上关键字static
作用: 改变作用域,与之相对的是extern(缺省情况)
内存:代码段
作用域:限定作用域为文件内
 
好处:
同静态全局变量一样,即可以禁止其他编译单元的调用,又能屏蔽可能存在的外部的同名函数,不要担心命名冲突
(跟普通的函数比仅仅是限制了作用域而已, 这个有待阅读C语言标准,想要调用还是可以的,通过函数指针;也有网友说静态函数所做的只是在汇编的时候把.globe符号给去掉了使得静态函数只在当前的文件中生效,有待继续看书)


存储说明符auto,register,extern,static,对应两种存储期:自动存储期和静态存储期。
 
auto和register对应自动存储期。具有自动存储期的变量在进入声明该变量的程序块时被建立,它在该程序块活动时存在,退出该程序块时撤销。

关键字extern和static用来说明具有静态存储期的变量和函数。用static声明的局部变量具有静态存储持续期(static storage duration),或静态范围(static extent)。虽然他的值在函数调用之间保持有效,但是其名字的可视性仍限制在其局部域内。静态局部对象在程序执行到该对象的声明处时被首次初始化。

由于static有以上特性,可实现一些特定功能。

1. 统计次数功能

声明函数的一个局部变量,并设为static类型,作为一个计数器,这样函数每次被调用的时候就可以进行计数。这是统计函数被调用次数的最好的办法,因为这个变量是和函数息息相关的,而函数可能在多个不同的地方被调用,所以从调用者的角度来统计比较困难。代码如下:

 
void count();
int main()
{
 int i;
 for (i = 1; i <= 3; i++)
  count();
  return 0;
}
void count()
{
static num = 0;
 num++;
 printf("第 %d次调用",num);
}
输出结果:

第1次调用
第2次调用
第3次调用

第一次调用
第一次调用