Is there existing Documentation about why the VBA Val function behaves differently than .Net implementation of same code (hex conversions)?
我正在从VBA转换代码,因此需要确认有关Val函数行为的证据,以便在.Net中忠实地复制它。
问题是这行VBA代码
1 | lHexNum = Val("&h" & HexNum) ' HexNum = 3B05000004F137 |
正在产生此输出
323895
应该是这个
16612521184391480
但我不知道为什么不是这样。
我在.Net中使用了2种方法来确认预期的输出16612521184391480(以及使用简单的十六进制计算器)。
1 | Convert.ToInt64(HexNum, 16); |
和
1 | Microsoft.VisualBasic.Conversion.Val("&h" + HexNum); |
但是,我仍然需要完美地复制VBA程序的实际输出,该程序现在可以输出323895的输出。
我能找到的唯一理由是,如果我从HexNum中删除了3B05,则将获得匹配的输出。由于我无法针对足够多的实时数据进行测试,无法100%确保此方法在所有情况下均有效,因此我无法使用此技巧。
没有人有参考或更多信息,关于Access 2003应用程序如何以及为什么从Val函数获取323895输出以及为什么即使匹配的Microsoft.VisualBasic.Conversion.Val方法也无法获得相同的输出?
好吧,
Val()返回一个Double。假设将lHexNum声明为32位长,则VBA将执行隐式转换,即使溢出也不会引发错误。由于VBA没有64位整数数据类型,因此它只会丢弃高字节。
VB6也是如此,我在下面验证了该结果是否返回您期望的值323895。
1 2 3 4 5 | Dim HexNum As String HexNum ="3B05000004F137" Dim lHexNum As Long lHexNum = Val("&h" & HexNum) Debug.Print lHexNum |
但是,在.NET中,Long是64位值。它能够保留整个十六进制值,因此不会丢掉任何东西。从技术上讲,这比VBA所做的更正确,因为在使用VBA进行转换期间,您丢失了一些原始数据。您也不能只将变量更改为Int32,因为如果运行时值太大,C#会抛出溢出异常。
如果想要与VBA / VB6相同的行为,则需要先将Double转换为Int64,然后再将其转换回Int32,以使其被截断。像这样:
1 | lHexNum = (Int32)(Int64)(Microsoft.VisualBasic.Conversion.Val("&h" + HexNum)); |
结果是Int64的高32位被丢弃,最终得到了所需的323895。
我使用的是Int64和Int32数据类型,以便更加明确,但是您也可以使用int代替Int32,并长期使用Int64。
您声明
在.NET中,
为了在.Net中获得相同的行为,您将需要屏蔽掉前32位:请参阅我要获取int64的低32位作为int32
例如
1 2 3 4 5 6 | Dim HexNumString ="3B05000004F137" Dim lHexNum As Long = CLng(Val("&h" & HexNumString)) Dim tempLong As Long = ((lHexNum >> 32) << 32) 'shift it right Then left 32 bits, which zeroes the lower half Of the Long Dim hexInt As Integer = CInt(lHexNum - tempLong) Debug.WriteLine(hexInt) |