ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

VBS中&H前缀十六进制数的陷阱

2022-03-31 12:31:29  阅读:436  来源: 互联网

标签:十六进制 Const 前缀 tw Long VBS http


标题: 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有