一个static修饰符惹得祸

      调试环境:xpsp3 vs2005

      最近在写一个小工具,中途遇到一个小bug,调试了我个把小时才完全搞清楚是怎么回事……下面是一段经过高度简化的代码:

#include "stdafx.h"
#include <iostream>
using namespace std;

void staticFunction(int i)
{
	static int nflag = i;

	cout << nflag << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
	for (int i = 0; i < 5; ++i)
	{
		staticFunction(i);
	}
	return 0;
}

      可以先猜测一下,这段代码的输出情况,是不是有一点点出乎意料。我机器上面的输出如下:

0
0
0
0
0

      为什么不是0 1 2 3 4呢?调试的时候发现,每次跟nflag赋值的时候,nflag的值没有任何变化,开始以为赋值前后有代码操作数据的时候越界了(原始代码是比较长的),检查了半天,把整个函数的代码几乎都删空了发现还是这样,后来发现nfag变量被static修饰,把static删除之后,逻辑正常了!

      这……这个static在这里,是因为之前nflag变量是个标志位变量,用来标注函数的状态的,后来因为修改之后通过传参数来设置状态,static忘记删除了。问题是为什么有static修饰时,赋值会失败呢?看来只有从汇编代码中找答案了……

static int nflag = i;
004113CE  mov         eax,dword ptr [$S1 (4171A0h)]
004113D3  and         eax,1
004113D6  jne         staticFunction+3Dh (4113EDh)
004113D8  mov         eax,dword ptr [$S1 (4171A0h)]
004113DD  or          eax,1
004113E0  mov         dword ptr [$S1 (4171A0h)],eax
004113E5  mov         eax,dword ptr [i]
004113E8  mov         dword ptr [nflag (41719Ch)],eax // 赋值

cout << nflag << endl;
004113ED  mov         esi,esp
004113EF  mov         eax,dword ptr [__imp_std::endl (4182A0h)]
004113F4  push        eax 
004113F5  mov         edi,esp
004113F7  mov         ecx,dword ptr [nflag (41719Ch)]
004113FD  push        ecx 
004113FE  mov         ecx,dword ptr [__imp_std::cout (41829Ch)]
00411404  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (418298h)]

      很明显,变量地址是0x41719C,但是给他赋值之前,先进行了一个判断,如果是已经赋值过了(根据存在0x4171A0下面的一个标志位),则再次进函数的时候就不再赋值了,直接使用(参考:004113D6  jne         staticFunction+3Dh (4113EDh))。

      后来查了下资料才知道这是C++的语法所规定的,函数里面的静态变量只能被初始化一次。去掉static修饰之后,代码就简单了:

/*static*/ int nflag = i;
004113CE  mov         eax,dword ptr [i]
004113D1  mov         dword ptr [nflag],eax

cout << nflag << endl;
004113D4  mov         esi,esp
004113D6  mov         eax,dword ptr [__imp_std::endl (4182A0h)]

     如果用常量初始化静态变量呢?如下:

004113CC  rep stos    dword ptr es:[edi]
static int nflag = 100;

cout << nflag << endl;
004113CE  mov         esi,esp
004113D0  mov         eax,dword ptr [__imp_std::endl (4182A0h)]
004113D5  push        eax 
004113D6  mov         edi,esp
004113D8  mov         ecx,dword ptr [nflag (417034h)]
004113DE  push        ecx 
004113DF  mov         ecx,dword ptr [__imp_std::cout (41829Ch)]
004113E5  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (418298h)]

      可以发现,直接就用了,看一下地址0x417034h的值,已经是100了,因此用常量赋值的情况,在编译时期,值就已经写到数据区了。

      【END】

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值