关于c#:是否存在有关为什么VBA Val函数的行为与.Net实现相同代码(十六进制转换)不同的文档?

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方法也无法获得相同的输出?


好吧,323895是(以十六进制表示)0004F137,因此,可以完全猜到这里的问题可能是您正在使用的Val(或:存储值的地方)是32位,并且因此只会提供最后8个字符的值(数据的最后4个字节)


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。


您声明lHexNum是VBA中的Long。这是32位,因此可以存储的最大值是2,147,483,6470x7FFFFFFF-这意味着您的0x3B05000004F137在VBA代码中被截断了。

在.NET中,Long为64位,因此十六进制值可以容纳并且不会发生截断。

为了在.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)