VBS中&H字首十六進位制數的陷阱
標題: VBS中&H字首十六進位制數的陷阱
作者: Demon
連結: http://demon.tw/programming/vbs-hex-constant.html
版權: 本部落格的所有文章,都遵守“署名-非商業性使用-相同方式共享 2.5 中國大陸”協議條款。
16進位制在程式設計中是很普遍的,在VBScript中,以“&H”字首來表示十六進位制數。
例如:
'Author: Demon 'Website: http://demon.tw 'Date: 2012/5/7 Const cr = ChrW(&HD) 'Carriage return Const lf = ChrW(&HA) 'Line feed Const HKCR = &H80000000 'HKEY_CLASSES_ROOT Const HKCU = &H80000001 'HKEY_CURRENT_USER Const HKLM = &H80000002 'HKEY_LOCAL_MACHINE Const HKU = &H80000003 'HKEY_USERS Const HKCC = &H80000005 'HKEY_CURRENT_CONFIG Const Normal = &H000 'Normal file Const ReadOnly = &H001 'Read-only fileConst Hidden = &H002 'Hidden file Const System = &H004 'System file Const Volume = &H008 'Disk drive volume label Const Directory = &H010 'Folder or directory Const Archive = &H020 'File has changed since last backup Const Alias = &H400 'Link or shortcut Const Compressed = &H800 'Compressed file
當這些以&H為字首的十六進位制值比較小或者僅用於位運算時,一切都很正常。但是當它們的值比較大時並且參與運算時,噩夢就開始了:
問題程式碼一:
'Author: Demon 'Website: http://demon.tw 'Date: 2012/5/7 For i = 0 To &HFFFF WScript.Echo ChrW(i) Next
這段程式碼的本意是輸出0到65535之間的Unicode字元,但是執行後卻沒有任何輸出。
問題程式碼二:
'Author: Demon 'Website: http://demon.tw 'Date: 2012/5/7 uni = 55401 ' &HD800 = 55296 &HDBFF = 56319 If (uni >= &HD800) And (uni <= &HDBFF) Then WScript.Echo uni 'do something End If
這是一個條件判斷語句,看似符合條件,結果還是沒有任何輸出。
問題程式碼三:
'Author: Demon 'Website: http://demon.tw 'Date: 2012/5/7 WScript.Echo AscW("魔") WScript.Echo MyAscW("魔") Function MyAscW(s) Dim n n = AscW(s) If n < 0 Then n = n + &HFFFF End If MyAscW = n End Function
如果字元的程式碼點(code point)大於32,767,那麼AscW函式會返回負數(詳見《AscW函式返回負數的問題》)。自定義函式MyAscW的本意是AscW的改進版,但是依然返回了負值。
例子就舉那麼多,不知道你看出問題所在了嗎?沒看出來也不要緊,讓我們一起來終結這個噩夢。
首先複習一下基礎知識,VBS中的整數型別分為Integer和Long,Integer的範圍是-32,768到32,767,Long的範圍是-2,147,483,648到2,147,483,647。可以知道,Integer是16位的,Long是32位的,並且兩者都是有符號數。
當&H字首十六進位制數比較小時,也就是&H0000到&H7FFF時,正好處於Integer正數的範圍之內。但是&H7FFF的下一個數&H8000(十進位制32768)超出了Integer所能表示的正數,這時候就會變成-32768,為什麼呢?
十六進位制的8000轉成二進位制是1000000000000000,16位中除了最高位是1以外,其他位都是0。最高位是1,你想到了什麼?沒錯,因為Integer是有符號數,所以最高位是符號位,0表示正數,1表示負數,所以得到的值當然是負數。於是從&H8000到&HFFFF之間的十六進位制數都是負數,依次為-32768到-1。
數字繼續增大,&HFFFF的下一個數&H10000已經不能用16位表示了,此時就用32位的Long表示,原理與Integer一樣。所以從&H10000到&H7FFFFFFF都是正數,對應32,768到2,147,483,647;&H80000000到&HFFFFFFFF都是負數,對應-2,147,483,648到-1。
現在32位都已經用完了,VBS沒有64位的整數,所以&H100000000及其之後的數會報錯:Microsoft VBScript compilation error: Syntax error。
OK,原理講完了,現在看上面的程式碼應該知道錯在哪裡了。那麼怎麼解決呢,難道所有用&H十六進位制數參與運算的地方都要改成十六進位制不成?
這的確是解決方法之一,只不過如果數值比較大的話程式碼會很長很難看而已,而且十進位制看起來沒有十六進位制那麼直觀。
這裡有一個我無意中搜索到的undocumented的技巧,那就是在&H十六進位制數後面再加上一個&,強制轉換成Long型別,這應該是從VB那裡繼承下來的吧。
'Author: Demon 'Website: http://demon.tw 'Date: 2012/5/7 x = &HFFFF y = &hFFFF& WScript.Echo x, TypeName(x) WScript.Echo y, TypeName(y)
順便提醒一句,這個技巧對於&H80000000到&HFFFFFFFF是沒有用的,因為它們本身就已經是Long了。
最後的最後,說一個很奇怪的地方,在&H0000到&HFFFF範圍內,除了&H8000(-32768)之外,其他數的型別(用TypeName函式)都是Integer,而&H8000的型別卻是Long:
'Author: Demon 'Website: http://demon.tw 'Date: 2012/5/7 x = &H8000 WScript.Echo x, TypeName(x)
可如果它是Long的話,應該是32768才對啊,為什麼還會是負值呢?百思不得其解,如果哪位高人知道,請留言指點一下。
參考連結:http://social.technet.microsoft.com/Forums/fi/ITCG/thread/673d7646-2fbb-45f2-be67-91717589a6f5
相關文章:
隨機文章:
- 88行程式碼實現俄羅斯方塊遊戲(含講解)
- 利用WMI打造完美“三無”後門-U盤偵測與Autorun
- MySQL字符集與排序方式
- _open_osfhandle函式
- VB6拾遺:內聯彙編與CallWindowProc函式
出處:http://demon.tw/programming/vbs-hex-constant.html