聚星亭

吾笨笨且懒散兮 急须改之而奋进
posts - 74, comments - 166, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

Static关键字学习笔记

Posted on 2009-12-27 21:12 besterChen 阅读(667) 评论(0)  编辑 收藏 引用 所属分类: C/C++/STL/boost

       以前总是对Static声明的变量(函数),感到困惑,因为课本中写的也比较模糊,弄的经常搞不懂啥时候该用静态变量。

课堂上,钱老师对这个问题做了比较透彻的讲解,对这个问题相关的知识点总结如下:

Title

1.         若给一个static变量初始化为一个常量,则在反汇编中见不到对这个变量的初始化代码。

a)         无论是全局还是局部的静态变量,它的内容都直接写在PE的数据段中。

2.         若给一个static变量初始化一个未知的变量,则它只初始化一次。后面的初始化内容对它不产生影响。

3.         全局静态的变量或者函数,其作用范围仅限于当前的CPP文件(局部静态变量作用范围同普通局部变量)

4.         静态的变量或者函数,其生命周期是整个程序的周期。

 

 对于静态成员的作用范围仅是当前CPP文件,这个限制应该仅是编译器级别的检查。

通过观察它的OBJ文件,可以发现,编译器对静态函数或者变量的名称做了改变。改变后的名称中包含了它的作用范围,类型等信息。

 同时,老师用C来模拟了只初始化一次的原理,由此我对静态这个词感觉了解了很多,为了证实钱老师将的内容。也为了加强自己对知识的理解,在这个笔记的同时,我对其进行反汇编。

static int TestStatic(int nStartIndex, int nEndIndex)

{

    static int nsStartNum = nStartIndex;         // 只初始化一次

    static int nsEndNum = nEndIndex;

 

    printf("%d\t%d\r\n", nsStartNum, nsEndNum);

 

    nsStartNum++;

    nsEndNum++;

 

    return 0;

}

int  g_nsGoNum = 100;       // 见不到这句代码对应的汇编代码。

int main()

{

    for (int n = 0; n < 10; n++)

    {

        TestStatic(n, 10-n);

    }

 

    return 0;

}

         程序输出的结果表明,参数只对这两个静态变量影响了一次,然后再就不起作用了。

OD加载,分析:

00401020  /$  A0 D8984000   mov     al, byte ptr [4098D8]            ;  检查标记

00401025  |.  A8 01          test    al, 1

00401027  |.  75 11           jnz     short 0040103A

00401029  |.  8B4C24 04      mov     ecx, dword ptr [esp+4]           ;  初始化静态变量

0040102D  |.  0C 01          or      al, 1                            ;  初始化以后,OR标记

0040102F  |.  A2 D8984000   mov     byte ptr [4098D8], al

00401034  |.  890D E0984000  mov     dword ptr [4098E0], ecx

0040103A  |>  A8 02         test    al, 2

0040103C  |.  75 11          jnz     short 0040104F

0040103E  |.  8B5424 08      mov     edx, dword ptr [esp+8]           ;  初始化第二个变量

00401042  |.  0C 02          or      al, 2                                                     ; 设置标志二

00401044  |.  A2 D8984000   mov     byte ptr [4098D8], al

00401049  |.  8915 DC984000 mov     dword ptr [4098DC], edx

0040104F  |>  A1 DC984000  mov     eax, dword ptr [4098DC]   ; 开始显示信息

00401054  |.  8B0D E0984000  mov     ecx, dword ptr [4098E0]

0040105A  |.  50            push    eax

0040105B  |.  51            push    ecx

0040105C  |.  68 30704000   push    offset < "%d\t%d\r\n">;

00401061  |.  E8 2A000000   call    <_printf>

         很明白了,它用了一个DOWRD来做标志位,初始化了就将对应的位做 按位或 运算。在初始化前,先检查对应的标记是否为 真,如果是,就不再对它进行初始化。

         如果觉得这个流程不清晰,可以看下面的流程图:


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理