以前总是对Static声明的变量(函数),感到困惑,因为课本中写的也比较模糊,弄的经常搞不懂啥时候该用静态变量。
课堂上,钱老师对这个问题做了比较透彻的讲解,对这个问题相关的知识点总结如下:
对于静态成员的作用范围仅是当前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来做标志位,初始化了就将对应的位做 按位或 运算。在初始化前,先检查对应的标记是否为 真,如果是,就不再对它进行初始化。
如果觉得这个流程不清晰,可以看下面的流程图: