|
|
导航: |
论坛 -> DELPHI技术
斑竹:liumazi,sephil |
|
作者: |
|
2019/3/5 17:21:55 |
标题: |
Delphi 的Cardinal类型减法运算有bug |
浏览:1912 |
|
加入我的收藏 |
楼主: |
//bug of Cardinal subtraction procedure TForm1.Button3Click(Sender: TObject); var c1,c2:Cardinal; w1,w2:Word; vs: TValueSign; ix:NativeInt; i64:Int64; begin c1 := 1; c2 := 2; w1 :=1; w2 := 2;
Assert(c1-c2<>-1); //Bug! c1-c2 should be -1 Assert(w1-w2=-1); //OK, as we expected
vs := Math.Sign(c1-c2); //will call: function Sign(const AValue: Int64): TValueSign; Assert(vs<>-1);//Bug, should be -1
ix := c1-c2; Assert(ix=-1);//ok, as we expedted
ix := w1-w2; Assert(ix=-1);//ok, as we expedted
i64 := c1-c2; Assert(i64<>-1);//Bug!, i64 should equal -1
i64 := w1-w2; Assert(i64=-1);//ok, as we expedted end;
已经上报EMB: https://quality.embarcadero.com/browse/RSP-23899
----------------------------------------------
UniKeeper V10.40 -- 您最贴心的个人数据管理助手 |
作者: |
|
2019/3/5 17:29:41 |
1楼: |
你不认识 正整数吗?回小学重新学一下吧。 不过 后面的 int64 的值,的确应该是 -1
也就是 i64 := c1-c2; 这个,你的确发现了 BUG。
----------------------------------------------
(C)(P)Flying Wang
|
作者: |
|
2019/3/5 18:41:50 |
3楼: |
Cardinal 和 unsigned int 等价,就是非负整数
----------------------------------------------
-
|
作者: |
|
2019/3/5 18:44:38 |
3楼: |
(UINT32 - UINT32)不做位宽提升的,所以结果还是UINT32,和-1不等价。INT64那个同理。
----------------------------------------------
-
|
作者: |
|
2019/3/5 19:19:54 |
4楼: |
(UINT32 - UINT32)我觉得是做了位宽提升的, 因为 Math.Sign(c1-c2) 调用的是 Sign(const AValue: Int64)而不是 Sign(const AValue: Integer).
我的汇编水平有限, 我觉得如果对比一下 ix := c1-c2 与 i64 := c1-c2的汇编代码可能能发现问题.
----------------------------------------------
UniKeeper V10.40 -- 您最贴心的个人数据管理助手
|
作者: |
|
2019/3/5 21:42:15 |
5楼: |
谁用64位测下 我看到10.3改过 win64 整数 出现垃圾值的说明
----------------------------------------------
[alias] co = clone --recurse-submodules up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/>http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
|
作者: |
|
2019/3/5 23:07:29 |
6楼: |
Delphi7下没问题
----------------------------------------------
是你上错了车,还是我下错了站?
|
作者: |
|
2019/3/5 23:33:14 |
7楼: |
i64 := c1 - c2; 的汇编
sub eax,dword ptr ss:[ebp-C] | c1 - c2 xor edx,edx | 0 mov dword ptr ss:[ebp-18],eax | i64低32bit为 0xFFFFFFFF(也就是c1-c2的结果) mov dword ptr ss:[ebp-14],edx | i64高32bit置零 cmp dword ptr ss:[ebp-14],FFFFFFFF | 验证高32bit是否为0xFFFFFFFF jne project1.5EB62C | cmp dword ptr ss:[ebp-18],FFFFFFFF | 验证低32bit是否为0xFFFFFFFF je project1.5EB642 |
最后i64的值就是0x00000000FFFFFFFF = 4294967295
也验证了3楼朋友说的,c1-c2的结果也是32bit,并存入了i64的低32bit中。
另外,assert里的表达式应该是你期望的表达式,应该书写为Assert(i64 = -1)
----------------------------------------------
-
|
作者: |
|
2019/3/6 8:38:22 |
8楼: |
综合起来我觉得应该有如下结论: 1. c1-c2 这个运算的结果数据类型, Delphi本意是要当成Int64的(后面分析), 这个运算分成了两步 1) 执行32的减法,得到FFFFFFFF 2) 扩展到 64位, 但这一步它做错了,不能简单把高32位置零, 要进行符号位扩展! 2.为什么说Delphi编译器本意是要将c1-c2结果设为Int64呢?有下面两个证据: 1) Math.Sign(c1-c2) 调用的是 function Sign(const AValue: Int64): TValueSign; 不是 function Sign(const AValue: Integer): TValueSign; 2) Assert(c1-c2=-1)会失败
----------------------------------------------
UniKeeper V10.40 -- 您最贴心的个人数据管理助手
|
作者: |
|
2019/3/6 8:45:36 |
9楼: |
…… 被禁用帐号,帖子内容自动屏蔽! ……
----------------------------------------------
该账号是个傻逼
|
作者: |
|
2019/3/6 9:36:41 |
11楼: |
都是一些基础的东西。居然又是汇编又是编译器的。
cardinal本身是无符号整型,无符号和无符号运算,结果必然也是无符号。 虽然二进制都是0xffffffff。你强转一下就成-1了,无非就是对最高位的解释罢了。
对于那个math.sign的调用,回去看看最基本的数据结构不就行了么? 人家一个32位无符号数赋值给一个64位的有符号数,这叫赋值兼容。赋值兼容你们居然会要求人家改变你的数据?
我觉得吧,基础知识真的是相当重要。
----------------------------------------------
--
|
作者: |
dmzn (dmzn) |
★☆☆☆☆ |
-
|
盒子活跃会员 |
|
2019/3/6 11:16:05 |
12楼: |
Assert(c1-c2<>-1); //c1 - c2的结果默认是一个cardinal变量,值为High(cardinal)
i64 := c1-c2; //等同于i64=Int64(cardinal),i64的值为High(cardinal) Assert(i64<>-1);//判定成立
----------------------------------------------
生活愉快.
|
作者: |
lfxsq (lfxsq) |
★☆☆☆☆ |
-
|
普通会员 |
|
2019/3/6 11:40:26 |
13楼: |
这个应该算bug
----------------------------------------------
-
|
作者: |
|
2019/3/6 11:50:17 |
14楼: |
…… 被禁用帐号,帖子内容自动屏蔽! ……
----------------------------------------------
该账号是个傻逼
|
作者: |
|
2019/3/6 12:45:21 |
15楼: |
反正 D7 就是个垃圾 XE8 都已经步入 垃圾堆了。 10.3.1 还是挺好用的。
----------------------------------------------
(C)(P)Flying Wang
|
作者: |
|
2019/3/6 12:49:54 |
15楼: |
刚测试的结果: ix := c1 - c2; //Delphi 7/10.3 64-bit ix = High(Cardinal)=4294967295 //Delphi 10.3 32-bit ix = -1; //Assert(ix = -1); //ok, as we expedted
i64 := c1 - c2; //Delphi 7/10.3 一样 ix = High(Cardinal)=4294967295 //Assert(i64 <> -1); //Bug!, i64 should equal -1
----------------------------------------------
Delphi4Linux Delphi三层/FireDAC 技术群:734515869 http://www.cnblogs.com/rtcmw
|
作者: |
|
2019/3/6 14:36:08 |
16楼: |
Delphi: 10.3.1, 32Bits OS: Win 7, 32Bits
procedure TForm1.Button5Click(Sender: TObject); var b1,b2:Byte; w1,w2:Word; c1,c2:Cardinal; i64:Int64; begin b1 := 1; b2 := 2; i64 := b1-b2; Assert(i64=-1);//OK
w1 := 1; w2 := 2; i64 := w1-w2; Assert(i64=-1);//OK
c1 := 1; c2 := 2; i64 := c1-c2; Assert(i64=-1);//Fail
end;
at least, we expect a coincident result
----------------------------------------------
UniKeeper V10.40 -- 您最贴心的个人数据管理助手
|
|