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
相关文章:
<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>随机文章:
- 88行代码实现俄罗斯方块游戏(含讲解)
- 利用WMI打造完美“三无”后门-U盘侦测与Autorun
- MySQL字符集与排序方式
- _open_osfhandle函数
- VB6拾遗:内联汇编与CallWindowProc函数
出处:http://demon.tw/programming/vbs-hex-constant.html
标签:十六进制,Const,前缀,tw,Long,VBS,http 来源: https://www.cnblogs.com/mq0036/p/16081183.html