1. 程式人生 > 其它 >VBS中&H字首十六進位制數的陷阱

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 file
Const 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

相關文章:

  1. VBS字串與UTF-16(Unicode)
  2. VBS For Next迴圈的陷阱
  3. 在VBS中定義位元組陣列Byte()
  4. VBS位元組陣列Byte()的處理方法
  5. VBS For Next迴圈的一些細節

隨機文章:

  1. 88行程式碼實現俄羅斯方塊遊戲(含講解)
  2. 利用WMI打造完美“三無”後門-U盤偵測與Autorun
  3. MySQL字符集與排序方式
  4. _open_osfhandle函式
  5. VB6拾遺:內聯彙編與CallWindowProc函式

 

 

出處:http://demon.tw/programming/vbs-hex-constant.html