妈的,关于 static 被网络上的信息带偏了,还以为自己理解错误呢

10阅读 0评论2025-07-10 snow888
分类:C/C++

为了给自己提个醒,记录如下:

2.6.2 static 变量
static变量是函数或文件中的永久变量。和全局变量不同,函数外或文件外看不到静态(static)变量;和全局量相同,函数调用之间,静态量保持其值。编写其它程序使用的通用函数或库函数时,这一特性是有用的。static对周部变量和全局变量的作用不一样。

2.6.3 static 局部变量
把 static作用于局部变量时,编译程序为之生成永久存储单元,很象全局变量。静态(static)局部变量和全局变量的主要区别在于可见性,静态局部量只在其被声明的代码块中是可见的。简言之,静态局部变量是多次函数调用之间保持其值的局部变量。
对某些必须在调用之间保持局部变量值的子程序而言,static局部变量特别重要。如果不允许使用static,则必须在这类函数中使用全局变量,由此开放引入副作用的门户。基于前次值生成下一个值的数列产生器要求使用static局部变量。否则,我们只好使用全局变量,每个程序中使用该函数时都要声明所用的全局变量,同时要确保与已声明的其它全局变量没有冲突。使用全局量的函数也难于放到库中。数列产生器函数的较好写法是使用static,如下所示:

点击(此处)折叠或打开

  1. series( void )
  2. {
  3.      static int series_num;

  4.      series.num=series_num+23:
  5.      return(series_num);
  6. }
本例中,变量series_num在调用之间一-直存在,不象普通局部变量那样进入函数时产生,退出函数时消失。这种手段使每次调用series()时都生成一个基于前次值的新数,同时又避免了使用全局变量。
首次进入代码块时给局部静态量赋初值,以后进入同一代码块时不再赋初值,具体实现如下例所示。初次进入新版series()时,把series_num 初始化成 100,以后进入时不再赋初值了。


点击(此处)折叠或打开

  1. series(void )
  2.         static int series_num=100:

  3.         series_num=series_num+23:
  4.         return(series_num):
  5. }
如函数所示,产生的序列总是从123开始。虽然某些应用中允许这样处理,但大多数序列生成子程序应该允许用户指定开始点。一种实现方法是把series_num()声明成全局变量,然后由另一个函数指定序列起点。然而,使用static的初衷就是不用全局变量,我们由此引入static 的第二种用法,如下节所示。

2.6.4 static 全局变量
施加于全局变量的 static 令编译程序生成静态(static)全局变量,使之仅在定义该变量的文件中是可见的。因此,虽然变量是全局的,但其它文件中的子程序无法感知其存在,无法修改之,有效地消除了副作用。在局部静态变量不能满足要求的罕见情况下,我们可以建立…个小文件,其中只放需要的静态全局变量的函数和所需的静态全局量,然后独立编译该文件,以后使用时不必担心副作用。
我们重写上节的序列产生器函数,由此允许通过称为series_start()的第二个函数置i  mam个种子值,由该种子值初始化序列的产生。放函数series(),series_start()和变量 series_num的全文件如下:


点击(此处)折叠或打开

  1. /* this must all be in one file -preferably by itself */
  2. static int series_num:
  3. void series_start(int seed);
  4. int series(void );

  5. series(void)
  6. {
  7.         series_num=series_num-23;
  8.         return(series_num):
  9. }

  10. /*initialize series_num */

  11. void series_start(int seed )
  12. {
  13.         series_num=seed:
  14. }
先用某个不确定值调用 series-start(),由此初始化序列发生器。随后,再逐次调用series(),
由此产生序列中的值。我们再次重复:局部静态量只在其被定义的函数或代码块中是可见的;全局静态量只在其被定义的文件中是可见的。如果把函数series()和series_start()放到库中,程序可以调用这两个函数,但不能直接引用静态全局变量series-num,因为series_num()对程序的其它代码是隐蔽的。实际上,在其它文件中可以用series-num为名字,声明并使用另--个全局变量。本质上,static修饰符允许声明仅由一个函数了解并使用的变量,在函数调用之间保持变
量值的同时又不影响其它函数。static 变量允许程序的一部分对其它部分充分隐蔽,管理大型复杂程序时的优点十分突出。
存储修饰符static使我们方便地构造通用函数,使函数便于放到库中。

=========================================
以上内容,摘抄自 《C语言大全第二版》

由此,我们得出如下结论:
1、使用 static 修饰的局部变量,会在内存中开辟一个永久的静态存储区域,当下次调用该函数时,该区域被再次重载,其值为上一次该函数运行后结果值。且不受该函数再次调用时在该函数内定义的影响。这句话可以理解为:
假设我们在某个函数中定义了一个静态的整型变量 i,并赋予了初始值 10 ,当再次调用该函数时,在定义这个静态整型变量 i 的地方的赋值语句将不会被执行,i 的值保持为上一次调用该函数后的 i 值,我们用如下的程序代码片段加以解释:

点击(此处)折叠或打开

  1. int func()
  2. {
  3.         static int i=10;

  4.         i = i + 5 ;
  5.         return(i);
  6. }
以上这个函数,在首次调用的时候,
static int i = 10 ;
将对 i赋予初始值 10 ; 
第二次调用这个函数,虽然会执行 static int i ; 但不会对 i 赋予初始值 10 ,反而是将首次调用结束后的 i 值 15 赋予了 i , 然后再次执行 i = i+5 。
也就是说,第二次调用结束后, i 的值变成了 20 。
 
2、使用 static 修饰的局部变量,如果没有显式进行赋值,则对于整型变量而言,其值为 0 , 对于指针或字符型而言,其值为 NULL。

我们可以用如下代码进行验证:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>


  4. int func()
  5. {
  6.         static int i;
  7.         ++i;
  8.         return(i);
  9. }


  10. int main ( void )
  11. {
  12.         printf("%d\n",func());
  13.         printf("%d\n",func());
  14.         printf("%d\n",func());
  15.         printf("%d\n",func());
  16.         return 0;
  17. }
执行的结果为:
1
2
3
4
上一篇:细思极恐,一个特别容易忽视的变量内容被修改的问题。
下一篇:某些操作系统上没有 timeout 命令,那就写一个