windows程序设计中的HEXCALC.c程序是个比较让人费脑子的程序,现在将一些一般人看这个程序会遇到的问题说一下:
这些问题集中在下面一段代码中:
case WM_CHAR:
if ((wParam = (WPARAM) CharUpper ((TCHAR *) wParam)) == VK_RETURN)
wParam = '=' ;
if (hButton = GetDlgItem (hwnd, wParam))
{SendMessage (hButton, BM_SETSTATE, 1, 0) ;
Sleep (100) ;
SendMessage (hButton, BM_SETSTATE, 0, 0) ;
}
else
{
MessageBeep (0) ;
break ;
}
// fall through
case WM_COMMAND:
SetFocus (hwnd) ;
if (LOWORD (wParam) == VK_BACK) //backspace
ShowNumber (hwnd, iNumber /= 16) ;
else if (LOWORD (wParam) == VK_ESCAPE) // escape
ShowNumber (hwnd, iNumber = 0) ;
else if (isxdigit (LOWORD (wParam))) // hex digit
{ if (bNewNumber)
{
iFirstNum = iNumber ;
iNumber = 0 ;
}
bNewNumber = FALSE ;
if (iNumber <= MAXDWORD >> 4)
ShowNumber (hwnd, iNumber = 16 * iNumber + wParam- (isdigit (wParam) ? '0': 'A' - 10)) ;
else
MessageBeep (0) ;
}
else // operation
{
if (!bNewNumber)
ShowNumber (hwnd, iNumber =CalcIt (iFirstNum, iOperation, iNumber)) ;
iOperation = LOWORD (wParam) ;
}
return 0 ;
第一个问题: if ((wParam = (WPARAM) CharUpper ((TCHAR *) wParam)) == VK_RETURN)
wParam = '=' ;这个是把回车转化为等于号,问题是只是把wParam = '=',并没有再发一个wParam = '='的消息呀?
答:注意wParam = '=' ;之后并没有return 0或break之类的,所以wParam被改为 '='之后并没有完,还要继续往下走,所以无需再发一个wParam = '='的消息。
第二个问题: else if (isxdigit (LOWORD (wParam))) 中的isxdigit (LOWORD (wParam)),isxdigit 是检查一个数是否为十六制数,所以通过LOWORD (wParam)传回来的数总能转化为十六制进数,所以isxdigit (LOWORD (wParam))总为真,else if (isxdigit (LOWORD (wParam)))总能被执行,后面的那个else将永还会被执行
答:isxdigit 是检查一个数是否为十六制数字,不是检查一个数是否为十六制数,十六制数字为 16进制数:0123456789abcdefABCDEF,即一个数不管它是什么进制,只有转化为十六进制后与那些数字相同,isxdigit才会传回非零值。
第三个问题: if (iNumber <= MAXDWORD >> 4)
ShowNumber (hwnd, iNumber = 16 * iNumber + wParam- (isdigit (wParam) ? '0': 'A' - 10)) ;
中MAXDWORD >> 4,MAXDWORD=0xFFFFFFFF;右移4位后为0xFFFFFFF,要iNumber <=0xFFFFFFF,是不是会使做运算的数位限制在28位,而不是32位。
答:这个问题纯属你计算错误,当iNumber达到了28位,即七个十六进制数字时,它仍然<= MAXDWORD >> 4,这时再进行后面的运算达到32位,即八个十六制进数字后,在做比较,就> MAXDWORD >> 4了,这时if (iNumber <= MAXDWORD >> 4)就不成立了,此时iNumber正好达到了32位
第四个问题: if (LOWORD (wParam) == VK_BACK) //backspace
ShowNumber (hwnd, iNumber /= 16) ;
else if (LOWORD (wParam) == VK_ESCAPE) // escape
ShowNumber (hwnd, iNumber = 0) ;
当按下第一个ESCAPE或BACK键时,iNumber的值并没有被初始化,这样调用了一个没有初始化的变量是否有问题?
答:iNumber被定义为static,凡是被定义为static的变量初始值为0,即使没有初始化,它的值也是0,而上面的代码在iNumber=0时完全可以。
第五个问题:当按下第一个数字按钮,iFirstNum = iNumber ;再接下往下按后面的数字按钮iNumber = 16 * iNumber + wParam -(isdigit (wParam) ? '0': 'A' - 10)),这时第一个被输入的数被分成了两次,第一个键按的数为存入了iFirstNum ,第一个键与后面的那个些共同形成的数被存入了iNumber ,当按下操作符键时,在没有键入新的操作数之前,上面的两个数就先操作了,这样岂不出问题?
答:不会出问题的,因为CalcIt (iFirstNum, iOperation, iNumber)) ;中iOperation初始值是'=',而 CalcIt (UINT iFirstNum, int iOperation, UINT iNum)函数在iOperation为'='时是 return iNum ,也就是说在进行输第二个数之前,虽然这个程序已经运行了一次 CalcIt 函数,但这次 CalcIt 函数并没有进行实际的运算,而只是把原来的数又返回了一遍。
第六个问题:当按下操作按钮后,第一次运行CalcIt 函数,但此时CalcIt 函数的iOperation变量并不是按下的操作按钮,而是'=',是不是不对呀?
答:很对呀,上面都说了,第一次运行CalcIt 函数时,第二个数都还没输入,此时的CalcIt 函数并没有作运算,只是将原来的数又返回去了,而且CalcIt 函数将iOperation的初始值变为你按下的运算按钮的值,此后在输完第二个数,再按下新的运算按钮,CalcIt 函数才会用头一次按下运算按钮的值进行上面的运算,并在运算完后把iOperation的值变成你按下的那个新的运算按钮的值。
第七个问题:ShowNumber (hwnd, iNumber = 16 * iNumber + wParam- (isdigit (wParam) ? '0': 'A' - 10)) ;中的wParam,为什么不是LOWORD (wParam),wParam的低16位是控件ID,也就是这个程序中按下数字按钮后形成的数,高16位是通知码,在很多资料上说控件产生的通知码是1呀,这么说来wParam与LOWORD (wParam)应该并不相等呀,因为wParam的高16位是1,LOWORD (wParam)没有高16位呀,也就是他的高16位可以说是0呀?
答:这个问题嘛,我也觉的有问题,可能是那些资料说的不对呀,反正我做了很多测试,结果发现在很多程序中按钮控件产生的WM_COMMAND消息的wParam,它的高16位确实是0,也就是说用按钮产生的消息中wParam和LOWORD (wParam)至少在这些程序中的值确实是相等的,只是位数不同。
第八个问题:ShowNumber (hwnd, iNumber = 16 * iNumber + wParam- (isdigit (wParam) ? '0': 'A' - 10)) ;,中如果wParam是阿拉伯数字的话,则iNumber = 16 * iNumber + wParam- 0;这好像不是按钮的标题上标的值吧,而是按钮的控件ID值,也就是那个标题上标的值的ASCii码表,这怎么能行呢?
答:你看清楚,减去的是'0',不是0,'0'是一个ASCii字符,他的值是48,所以比如按下了带1的按钮,它的ID值是49,减去'0'正好是1,后面的那个'A' - 10也差不多的情况,就不再介绍了。
好了,常见的那些问题都回答完毕,有不明白的可以问。