其他分享
首页 > 其他分享> > 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,为什么呢?

<iframe data-google-container-id="a!4" data-google-query-id="CIzepOyx7_YCFR1BwgUdTK8Jhg" data-load-complete="true" frameborder="0" height="0" id="aswift_3" marginheight="0" marginwidth="0" name="aswift_3" scrolling="no" src="https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-8762243733943533&output=html&h=280&adk=894127882&adf=4038516392&pi=t.aa~a.3085134403~i.34~rp.4&w=600&fwrn=4&fwrnh=100&lmt=1648696705&num_ads=1&rafmt=1&armr=3&sem=mc&pwprc=5254972129&psa=1&ad_type=text_image&format=600x280&url=http%3A%2F%2Fdemon.tw%2Fprogramming%2Fvbs-hex-constant.html&fwr=0&pra=3&rh=150&rw=600&rpe=1&resp_fmts=3&wgl=1&fa=27&dt=1648696705852&bpp=3&bdt=3264&idt=3&shv=r20220329&mjsv=m202203230101&ptt=9&saldr=aa&abxe=1&cookie=ID%3D99605329bb2ea48e-22bd18cf6bd1000b%3AT%3D1648696705%3ART%3D1648696705%3AS%3DALNI_Ma2fR1qhzWe8JtNqaVzWpE60U-Gpw&prev_fmts=0x0&prev_slotnames=1210634645%2C8004075020&nras=2&correlator=3744948654663&frm=20&pv=1&ga_vid=929646997.1648696704&ga_sid=1648696704&ga_hid=1385054104&ga_fc=1&u_tz=480&u_his=1&u_h=864&u_w=1536&u_ah=824&u_aw=1536&u_cd=24&u_sd=1.25&adx=455&ady=2142&biw=1519&bih=666&scr_x=0&scr_y=0&eid=44759875%2C44759926%2C44759842%2C44761043%2C31062930&oid=2&pvsid=4124143208276995&pem=686&tmod=460661772&uas=0&nvt=1&ref=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DcmwGDL_7r9KG-PobGj3r1ZB6h3oHi5B13ieQlaMjHy7lmN1F_Oz-Hu5jszzHzxNCo-oveV2a6E74IlPpBpXPg_%26wd%3D%26eqid%3Db2b085e50000923e0000000562451cf7&eae=0&fc=1408&brdim=0%2C0%2C0%2C0%2C1536%2C0%2C1536%2C824%2C1536%2C666&vis=1&rsz=%7C%7Cs%7C&abl=NS&fu=128&bc=23&ifi=4&uci=a!4&btvi=1&fsb=1&xpc=S0TN8ZuIZr&p=http%3A//demon.tw&dtd=19" style="left: 0; position: absolute; top: 0; border: 0; width: 600px; height: 0" width="600"></iframe>

十六进制的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那里继承下来的吧。

<iframe data-google-container-id="a!5" data-google-query-id="CNHBseyx7_YCFdYCXAod56QJvg" data-load-complete="true" frameborder="0" height="0" id="aswift_4" marginheight="0" marginwidth="0" name="aswift_4" scrolling="no" src="https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-8762243733943533&output=html&h=280&adk=894127882&adf=3856571147&pi=t.aa~a.3085134403~i.46~rp.4&w=600&fwrn=4&fwrnh=100&lmt=1648696706&num_ads=1&rafmt=1&armr=3&sem=mc&pwprc=5254972129&psa=1&ad_type=text_image&format=600x280&url=http%3A%2F%2Fdemon.tw%2Fprogramming%2Fvbs-hex-constant.html&fwr=0&pra=3&rh=150&rw=600&rpe=1&resp_fmts=3&wgl=1&fa=27&dt=1648696705857&bpp=1&bdt=3270&idt=0&shv=r20220329&mjsv=m202203230101&ptt=9&saldr=aa&abxe=1&cookie=ID%3D99605329bb2ea48e-22bd18cf6bd1000b%3AT%3D1648696705%3ART%3D1648696705%3AS%3DALNI_Ma2fR1qhzWe8JtNqaVzWpE60U-Gpw&prev_fmts=0x0%2C600x280%2C1519x666&prev_slotnames=1210634645%2C8004075020&nras=4&correlator=3744948654663&frm=20&pv=1&ga_vid=929646997.1648696704&ga_sid=1648696704&ga_hid=1385054104&ga_fc=1&u_tz=480&u_his=1&u_h=864&u_w=1536&u_ah=824&u_aw=1536&u_cd=24&u_sd=1.25&adx=455&ady=2465&biw=1519&bih=666&scr_x=0&scr_y=0&eid=44759875%2C44759926%2C44759842%2C44761043%2C31062930&oid=2&pvsid=4124143208276995&pem=686&tmod=460661772&uas=0&nvt=1&ref=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DcmwGDL_7r9KG-PobGj3r1ZB6h3oHi5B13ieQlaMjHy7lmN1F_Oz-Hu5jszzHzxNCo-oveV2a6E74IlPpBpXPg_%26wd%3D%26eqid%3Db2b085e50000923e0000000562451cf7&eae=0&fc=1408&brdim=0%2C0%2C0%2C0%2C1536%2C0%2C1536%2C824%2C1536%2C666&vis=1&rsz=%7C%7Cs%7C&abl=NS&fu=128&bc=23&ifi=5&uci=a!5&btvi=2&fsb=1&xpc=ZM4AiCkODk&p=http%3A//demon.tw&dtd=218" style="left: 0; position: absolute; top: 0; border: 0; width: 600px; height: 0" width="600"></iframe>
'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循环的一些细节
<iframe data-google-container-id="a!6" data-google-query-id="CKOdne-x7_YCFYsDXAodLxkIdw" data-load-complete="true" frameborder="0" height="0" id="aswift_5" marginheight="0" marginwidth="0" name="aswift_5" scrolling="no" src="https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-8762243733943533&output=html&h=280&adk=3555713595&adf=1635783871&pi=t.aa~a.758779223~rp.4&w=600&fwrn=4&fwrnh=100&lmt=1648696712&rafmt=1&to=qs&pwprc=5254972129&psa=1&format=600x280&url=http%3A%2F%2Fdemon.tw%2Fprogramming%2Fvbs-hex-constant.html&fwr=0&pra=3&rpe=1&resp_fmts=3&wgl=1&fa=40&dt=1648696705860&bpp=1&bdt=3273&idt=1&shv=r20220329&mjsv=m202203230101&ptt=9&saldr=aa&abxe=1&cookie=ID%3D99605329bb2ea48e-22bd18cf6bd1000b%3AT%3D1648696705%3ART%3D1648696705%3AS%3DALNI_Ma2fR1qhzWe8JtNqaVzWpE60U-Gpw&prev_fmts=0x0%2C600x280%2C1519x666%2C600x280&prev_slotnames=1210634645%2C8004075020&nras=5&correlator=3744948654663&frm=20&pv=1&ga_vid=929646997.1648696704&ga_sid=1648696704&ga_hid=1385054104&ga_fc=1&u_tz=480&u_his=1&u_h=864&u_w=1536&u_ah=824&u_aw=1536&u_cd=24&u_sd=1.25&adx=455&ady=3069&biw=1519&bih=666&scr_x=0&scr_y=426&eid=44759875%2C44759926%2C44759842%2C44761043%2C31062930&oid=2&pvsid=4124143208276995&pem=686&tmod=460661772&uas=0&nvt=1&ref=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DcmwGDL_7r9KG-PobGj3r1ZB6h3oHi5B13ieQlaMjHy7lmN1F_Oz-Hu5jszzHzxNCo-oveV2a6E74IlPpBpXPg_%26wd%3D%26eqid%3Db2b085e50000923e0000000562451cf7&eae=0&fc=1920&brdim=0%2C0%2C0%2C0%2C1536%2C0%2C1536%2C824%2C1536%2C666&vis=1&rsz=%7C%7Cs%7C&abl=NS&fu=128&bc=23&ifi=6&uci=a!6&btvi=3&fsb=1&xpc=gRfW7epUXi&p=http%3A//demon.tw&dtd=6178" style="left: 0; position: absolute; top: 0; border: 0; width: 600px; height: 0" width="600"></iframe>

随机文章:

  1. 88行代码实现俄罗斯方块游戏(含讲解)
  2. 利用WMI打造完美“三无”后门-U盘侦测与Autorun
  3. MySQL字符集与排序方式
  4. _open_osfhandle函数
  5. VB6拾遗:内联汇编与CallWindowProc函数

 

 

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

标签:十六进制,Const,前缀,tw,Long,VBS,http
来源: https://www.cnblogs.com/mq0036/p/16081183.html