奇怪的溢出问题,劳烦高人解惑。

dugubinghan 2009-02-10 12:25:44
刚刚写一个小程序的时候出现一个莫名的溢出错误,为了找出原因于是又写了一段测试代码;
且看我细细说来;
首先我有一个这样的计算:
Function test()
Dim m As Integer
Dim k As Integer
k = 9
m = 3641 * k
Stop
End Function
大家知道,3641×9=32769 大于interger 32768的上限,于是俺就将M改为long型:

Function test()
Dim m As Long
Dim k As Integer
k = 9
m = 3641 * k
Stop
End Function

这里,依然会报溢出错误;
如果这样写呢,
m = 3641 * 9
依然报错,我想估计是这里乘数的问题了,于是就这样写:
Function test()
Dim m As Long
Dim k As Long
k = 9
m = 3641 * k
Stop
End Function
OK了,不报错,看来就是乘数必须也要在共同的不溢出数据类型下面了。
这个特性有点奇怪也,麻烦高人解惑。
...全文
256 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
moke520 2010-03-10
  • 打赏
  • 举报
回复
VB 还没有自动化到防傻瓜的程度。
hehe
king3538 2009-03-28
  • 打赏
  • 举报
回复
学习
dugubinghan 2009-02-10
  • 打赏
  • 举报
回复
谢谢各位仁兄的热心讨论,让小弟学习到了这么多东西,结贴,给分。
dugubinghan 2009-02-10
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 SYSSZ 的回复:]
问题是这样也溢出

VB codePrivate Sub Form_Load()
Dim m As Long
m = 3641 * 9
End Sub

[/Quote]

因为3641,9都是integer的类型,计算中间结果也是,这里自然也就溢出了。
dugubinghan 2009-02-10
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 Tiger_Zhao 的回复:]
居然还有人说 VB6 是解释执行的。
无论是 VB-IDE 中的即时编译,还是编译成 exe 执行,语句 m = 9 * 3641 都要编程成两个大步骤:做乘法,将运算结果赋值到 m。
乘法指令 IMUL 分别对 8位、16位、32位运算有不同的指令,编译器只检查两个运算数的类型,全是 Integer 就用 16位 IMUL,有 Long 就用 32位 IMUL,即不预测运算结果的取值范围,也不关心运算结果要赋值的变量是什么类型。
VC 或其它语言的编译器基本也是按照这种…
[/Quote]

Tiger_Zhao 说的非常对,vb6里确实是这样处理的。
SYSSZ 2009-02-10
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 of123 的回复:]

不能说是 Bug。

VB 是自动进行类型转换的,但有些情况下,需要人工干预。

在 C 下,你也要 m = (unsigned long*)(k * 3641)

我也细细说来。VB 是解释执行的,赋值语句是从右向左执行,且缺省的缓存空间类型是 Integer 型。

当你计算 m = 3641 * k 时,首先根据等号右边运算数的类型,开出一个缓存空间。因为 k 是 Integer 型,它开出的缓存也是 Integer 型。当 CPU 算出结果后,要放进缓存时,溢出就发生了。这…
[/Quote]
问题是这样也溢出
Private Sub Form_Load()
Dim m As Long
m = 3641 * 9
End Sub
mfkinfo 2009-02-10
  • 打赏
  • 举报
回复
我想Variant的问题在于它可以是任意类型,具体的类型VB自动适应,这样一来3641为整型,k值也为整型,自然溢出啦。
dugubinghan 2009-02-10
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 mfkinfo 的回复:]
我一直比较佩服赵兄的,按的解释,如下代码应该行的通了,再试一下吧。
m = 3641 *clng( k )
[/Quote]

这样是OK的。。原因正如前面所说。
dugubinghan 2009-02-10
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 Tiger_Zhao 的回复:]
居然还有人说 VB6 是解释执行的。
无论是 VB-IDE 中的即时编译,还是编译成 exe 执行,语句 m = 9 * 3641 都要编程成两个大步骤:做乘法,将运算结果赋值到 m。
乘法指令 IMUL 分别对 8位、16位、32位运算有不同的指令,编译器只检查两个运算数的类型,全是 Integer 就用 16位 IMUL,有 Long 就用 32位 IMUL,即不预测运算结果的取值范围,也不关心运算结果要赋值的变量是什么类型。
VC 或其它语言的编译器基本也是按照这种…
[/Quote]

vb.net实际上还是有点区别的,在C#的编译器对整数的计算使用的是不带检验的IL指令,而VB.NET则使用的是待检验的IL指令。比如C#使用的是mul指令,而VB.NET则使用的是mul.ovf指令。也许C#默认不检测溢出而交由程序员来预期吧.
dugubinghan 2009-02-10
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 m60a1 的回复:]
不是VB的BUG

VB是有默认数据类型的,它能把所有的变量自适应成相应的数据类型

所以在处理大数的计算上面,既然把所有的变量都明示了出来那么就需要变量类型的一致性

如果像上面的例子

dim k
dim m

还会有上面的"BUG"吗???
[/Quote]

这样不会出错,但是这个又涉及到另外的一个问题了。
dim k 这样定义的K是个Variant,对于Variant,他可以说VB6里面任何一种数据类型,所以说这里的中间变量也是variant,自然不会溢出。
mfkinfo 2009-02-10
  • 打赏
  • 举报
回复
我一直比较佩服赵兄的,按他的解释,如下代码应该行得通了,再试一下吧。
m = 3641 *clng( k )
计算过程应该是k→long,3641→long,得long类型
3641VB应自动示别为inter类型,与long类型运算时自动转换为long类型。
k就要强制转换了。
vbman2003 2009-02-10
  • 打赏
  • 举报
回复
支持of123,关键是这样的运算VB是先按等号右边的最大值数据类型,开出一个缓存空间,下面不会错:
Dim m As Long
Dim k As Integer
k = 9
m = 364130 * k
mfkinfo 2009-02-10
  • 打赏
  • 举报
回复
我一直比较佩服赵兄的,按的解释,如下代码应该行的通了,再试一下吧。
m = 3641 *clng( k )
Tiger_Zhao 2009-02-10
  • 打赏
  • 举报
回复
居然还有人说 VB6 是解释执行的。
无论是 VB-IDE 中的即时编译,还是编译成 exe 执行,语句 m = 9 * 3641 都要编程成两个大步骤:做乘法,将运算结果赋值到 m。
乘法指令 IMUL 分别对 8位、16位、32位运算有不同的指令,编译器只检查两个运算数的类型,全是 Integer 就用 16位 IMUL,有 Long 就用 32位 IMUL,即不预测运算结果的取值范围,也不关心运算结果要赋值的变量是什么类型。
VC 或其它语言的编译器基本也是按照这种规则来做的。
dugubinghan 2009-02-10
  • 打赏
  • 举报
回复
这里依然会错。。。因为不是数据类型转换的错误。
dugubinghan 2009-02-10
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 of123 的回复:]
......
因此,在计算中结果会大于 Integer 时,可以这样:

Dim m As Long

m = 9
m = 9 * 3641

[/Quote]
谢谢 仁兄!
不过呢,
Dim m As Long
m = 9
m = 9 * 3641
这样依然是会报错的。

刚刚和同事讨论了下,发现是由于VB6计算先是计算出中间结果,然后再转换成为最终变量的数据类型,这里存在一个隐式的数据转换。
所以呢,在上面的式子中,9,3641在VB6中默认为integer类型,所以计算的中间结果也是interger型,然而在计算这个中间结果的时候就溢出了。

这个算作VB6的一个设计定义的fault吧。。。呵呵

谢谢大家捧场。。
mfkinfo 2009-02-10
  • 打赏
  • 举报
回复
可能问题就出在自动转换上,试试:
m = clng(3641 * k )
m60a1 2009-02-10
  • 打赏
  • 举报
回复
不是VB的BUG

VB是有默认数据类型的,它能把所有的变量自适应成相应的数据类型

所以在处理大数的计算上面,既然把所有的变量都明示了出来那么就需要变量类型的一致性

如果像上面的例子

dim k
dim m

还会有上面的"BUG"吗???
bind888 2009-02-10
  • 打赏
  • 举报
回复
友情up
zz005 2009-02-10
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 Tiger_Zhao 的回复:]
居然还有人说 VB6 是解释执行的。
无论是 VB-IDE 中的即时编译,还是编译成 exe 执行,语句 m = 9 * 3641 都要编程成两个大步骤:做乘法,将运算结果赋值到 m。
乘法指令 IMUL 分别对 8位、16位、32位运算有不同的指令,编译器只检查两个运算数的类型,全是 Integer 就用 16位 IMUL,有 Long 就用 32位 IMUL,即不预测运算结果的取值范围,也不关心运算结果要赋值的变量是什么类型。
VC 或其它语言的编译器基本也是按照这种规…
[/Quote]

Tiger_Zhao好厉害。面对什么都很强
加载更多回复(6)

2,506

社区成员

发帖
与我相关
我的任务
社区描述
VBA(Visual Basic for Applications)是Visual Basic的一种宏语言,是在其桌面应用程序中执行通用的自动化(OLE)任务的编程语言。
社区管理员
  • VBA
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧