总算知道为什么 VB 默认有整数溢出检查了。

tmp00000 UID.995403
2017-10-08 发表

本帖最后由 tmp00000 于 2017-10-8 17:04 编辑

最近 GitHub 的 microsoft/vblang 有个讨论很有意思。是关于 For 循环具体实现的。传送门: ***链接停止解析***
看下面这段代码:

[mw_shl_code=vbnet,true]For i As Byte = Byte.MinValue To Byte.MaxValue
UseByte(i)
Next[/mw_shl_code]

乍一看没什么问题。但是仔细想想 For 循环怎么实现的?看看 VB 团队老大 AnthonyDGreen 给的 For 循环实现说明:

[mw_shl_code=vbnet,true]Dim i = Byte.MinValue
Goto Test
Body:
UseByte(i)

i += 1
Test:
If i <= Byte.MaxValue Then Goto Body[/mw_shl_code]

这样就能看出问题了。当 i = 255 的时候, 循环还没结束就给它加一了。这样会引起溢出。如果没有整数溢出检查,这个循环就是个非常隐蔽的死循环。不熟悉的人很容易被这种死循环困扰很久。

敬告:
为防止不可控的内容风险,本站已关闭新用户注册,新贴的发表及评论;
你现在看到的内容只是互联网用户曾经发表的言论快照,仅用于老用户留存纪念,且仅与科技行业相关,全部内容不代表本站观点及立场;
本站重新开放前已针对包括用户隐私、版权保护、信息安全、国家政策在内的各种互联网法律法规要求,执行了隐患内容的自查、屏蔽和删除;
本站目前所属个人主体,未有任何盈利安排与计划,且与原WFUN.COM所属公司不存在任何关联关系;
如果本帖内容或者相关资源侵犯到您的合法权益,或者您认为存在问题,那么请您务必点此举报或投诉!
全部回复:
mei****hao UID.2852056
2017-10-08 使用 Lumia 950 回复

66666那么在哪里可以用到呢

vbfool UID.352791
2017-10-08 回复

确实,这个和C#的for实现起来还不一样,C#是把条件判断放在I+=1那句之前的。

这个记得也是当初.NET文档里写过的吧,VB和C#的区别之一,所以C#的循环经常是I=0,vb的循环经常是I=1这样。

tmp00000 UID.995403
2017-10-08 回复

本帖最后由 tmp00000 于 2017-10-8 22:33 编辑

Quotevbfool 发表于 2017-10-8 18:40 确实,这个和C#的for实现起来还不一样,C#是把条件判断放在I+=1那句之前的。 这个记得也是当初.NET文档里 ...
C# 通常是 for(byte i=byte.MinValue;i<byte.MaxValue;i++) UseValue(i); 而不是 for(byte i=byte.MinValue;i<=byte.MaxValue;i++) UseValue(i); 因为后者跟 vb 的 For i=Byte.MinValue To Byte.MaxValue 是一样的。

tmp00000 UID.995403
2017-10-08 回复

Quotemeibaihao 发表于 2017-10-8 17:15
66666那么在哪里可以用到呢


哪里可以用到?如果你写出那种看着好像不会溢出实际上溢出的代码就会觉得整数溢出检查在调试阶段非常有用。

tmp00000 UID.995403
2017-10-08 回复

Quotevbfool 发表于 2017-10-8 18:40
确实,这个和C#的for实现起来还不一样,C#是把条件判断放在I+=1那句之前的。

这个记得也是当初.NET文档里 ...


这个问题跟从1开始没什么关系。 如果去掉整数溢出检查, For i As Byte = 1 To Byte.MaxValue Console.WriteLine(i) Next 也是死循环。

TonyDeng UID.2870126
2017-10-08 回复

这是C/CPP的常见问题啊,必学须知的。

TonyDeng UID.2870126
2017-10-08 回复

本帖最后由 TonyDeng 于 2017-10-8 23:37 编辑

在.NET中,Byte是无符号8位整数,SByte是有符号8位整数。有无符号的区别在于编译器视其最高位是否为符号位,对有符号的整数,当其最高位为1时,视为负数,所以有符号8位整数的MaxValue=127(BIN:01111111),而无符号8位整数则是255(BIN:11111111),.NET类库自身的运算法则,对Byte类型进行运算结果仍然是Byte,Byte.MaxValue+1的结果是1,即255+1=256反转减去255是1,于是死循环。
***图片停止解析***

TonyDeng UID.2870126
2017-10-08 回复

稍微修改一下代码:
***图片停止解析***

TonyDeng UID.2870126
2017-10-09 回复

VB是没有无符号整数的,用C系写的.net类库代码,如果想顺利兼容VB,必须选择带符号数据类型。其实C++编程规范也有一条,就是“尽量使用int类型”,亦即少用unsigned int类型,一旦用unsinged,那么就必须非常警觉溢出问题,《C缺陷与陷阱》中最开头就是这个话题。最简单的解决办法是把数据尺寸往上升一级。

tmp00000 UID.995403
2017-10-09 回复

QuoteTonyDeng 发表于 2017-10-9 00:00
VB是没有无符号整数的,用C系写的.net类库代码,如果想顺利兼容VB,必须选择带符号数据类型。其实C++编程规 ...


没学好vb就别发这种回复。免得我们这些学好的笑话你。https://docs.microsoft.com/zh-cn/dotnet/visual-basic/

tmp00000 UID.995403
2017-10-09 回复

QuoteTonyDeng 发表于 2017-10-9 00:00
VB是没有无符号整数的,用C系写的.net类库代码,如果想顺利兼容VB,必须选择带符号数据类型。其实C++编程规 ...


带符号的也可以溢出。不信你试试。

tmp00000 UID.995403
2017-10-09 回复

QuoteTonyDeng 发表于 2017-10-8 23:35
在.NET中,Byte是无符号8位整数,SByte是有符号8位整数。有无符号的区别在于编译器视其最高位是否为符号位 ...


是这个道理。这样就构成了隐蔽的死循环。

TonyDeng UID.2870126
2017-10-09 回复

Quotetmp00000 发表于 2017-10-9 12:43
是这个道理。这样就构成了隐蔽的死循环。


其实你回我第一个帖子的时候,应该先看看我连续回的几个,再说那样的话。我C/C++用了二十多年,这么点溢出的问题岂有不知道之理,VB如何我的确不知道,但你们所说的那个溢出现象就是这样来的,在C/C++中就是最基本的东西。你那边的解决办法是用代码检测,而我这里提出的解决办法是数据扩容,前者是耗用时间,後者是耗用空间,都要花费代价,具体选用哪个,根据实际情况衡量。有无符号当然都会出现溢出,祇不過两者的容量差了一倍,有符号数更容易到达边界罢了,但有符号数不会在这样的循环代码中造成死循环。

tmp00000 UID.995403
2017-10-09 回复

QuoteTonyDeng 发表于 2017-10-9 12:52
其实你回我第一个帖子的时候,应该先看看我连续回的几个,再说那样的话。我C/C++用了二十多年,这么点溢 ...


其实1楼的 VB 代码已经在用无符号类型了。Byte 就是 System.Byte。你对于溢出的解释是正确的。设计 VB 的那些人知道 C++ 和 C# 有这些坑,所以才让 VB 默认有整数溢出检查。

tmp00000 UID.995403
2017-10-09 回复

QuoteTonyDeng 发表于 2017-10-9 12:52
其实你回我第一个帖子的时候,应该先看看我连续回的几个,再说那样的话。我C/C++用了二十多年,这么点溢 ...


有符号数照样会遇到这种问题。 for (sbyte i = sbyte.MinValue; i <= sbyte.MaxValue; i++) WriteLine(i); 这也是死循环。

vbfool UID.352791
2017-10-09 回复

本帖最后由 vbfool 于 2017-10-9 19:35 编辑

Quote***链接停止解析***
C# 通常是 for(byte i=byte.MinValue;i


我说的是习惯问题,for循环里i经常就是计数用的,为了要跑100遍,习惯性的这么写。

又仔细看了一下,我发现我说的不是整数溢出有关的东西,和本帖关系不大了。

artfly08 UID.2900999
2018-06-26 使用 Lumia 950 XL 回复

支持开发者

artfly08 UID.2900999
2018-07-14 使用 Lumia 950 XL 回复

太专业,支持

本站使用Golang构建,点击此处申请开源鄂ICP备18029942号-4联系站长投诉/举报