delphi – 为什么两个TBytes不能使用重叠的数据?
考虑以下XE6代码。目的是ThingData应该写入Thing1& Th2,但不是。这是为什么?
program BytesFiddle; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type TThing = class private FBuf : TBytes; FData : TBytes; function GetThingData: TBytes; function GetThingType: Byte; public property ThingType : Byte read GetThingType; property ThingData : TBytes read GetThingData; constructor CreateThing(const AThingType : Byte; const AThingData: TBytes); end; { TThing1 } constructor TThing.CreateThing(const AThingType : Byte; const AThingData: TBytes); begin SetLength(FBuf,Length(AThingData) + 1); FBuf[0] := AThingType; Move(AThingData[0],FBuf[1],Length(AThingData)); FData := @FBuf[1]; SetLength(FData,Length(FBuf) - 1); end; function TThing.GetThingData: TBytes; begin Result := FData; end; function TThing.GetThingType: Byte; begin Result := FBuf[0]; end; var Thing1,Thing2 : TThing; begin try Thing1 := TThing.CreateThing(0,TEncoding.UTF8.GetBytes('Sneetch')); Thing2 := TThing.CreateThing(1,TEncoding.UTF8.GetBytes('Star Belly Sneetch')); Writeln(TEncoding.UTF8.GetString(Thing2.ThingData)); Writeln(Format('Type %d',[Thing2.ThingType])); Writeln(TEncoding.UTF8.GetString(Thing1.ThingData)); Writeln(Format('Type %d',[Thing1.ThingType])); ReadLn; except on E: Exception do Writeln(E.ClassName,': ',E.Message); end; end. 解决方法
让我来了解一下这个代码失败的方式,以及编译器如何让你在脚下拍摄自己。
如果您使用调试器浏览代码,您可以看到会发生什么。 在Thing1初始化之后,您可以看到FData已经填满了所有的零。 在奇怪命名的构造函数CreateThing中,你有以下一行: FData := @FBuf[1]; 这看起来像一个简单的赋值,但是真的是调用DynArrayAssign Project97.dpr.32: FData := @FBuf[1]; 0042373A 8B45FC mov eax,[ebp-$04] 0042373D 83C008 add eax,$08 00423743 8B5204 mov edx,[edx+$04] 00423746 42 inc edx 00423747 8B0DE03C4000 mov ecx,[$00403ce0] 0042374D E8E66DFEFF call @DynArrayAsg <<-- lots of stuff happening here. DynArrayAsg执行的检查之一是检查源动态数组是否为空。 我们先看看the structure of a dynamic array;它不仅仅是一个数组的简单指针! Offset 32/64 | Contents --------------+-------------------------------------------------------------- -8/-12 | 32 bit reference count -4/-8 | 32 or 64 bit length indicator 0/ 0 | data of the array. 执行FData = @FBuf [1]你正在搞乱动态数组的前缀字段。 -8 (refcnt) -4 (len) 0 (data) FBuf: 01 00 00 00 08 00 00 00 00 'S' 'n' ..... FData: 00 00 00 08 00 00 00 00 .............. //Hey that's a zero length. 糟糕的是,当DynArrayAsg开始调查时,它看到它认为的是源的分配长度为零,即认为源是空的,不分配任何东西。它使FData保持不变! Thing2是否按预期工作? 你已经成功地将运行时欺骗了@FBuf [1]是对动态数组的有效引用。 -8 (refcnt) -4 (len) 0 (data) FBuf: 01 01 00 00 13 00 00 00 01 'S' 'n' ..... FData: 01 00 00 13 00 00 00 01 'S' .............. Oops FData现在有318,767,105的计数,长度为16,777,216字节。 这就是为什么你需要调用SetLength来消除大量的内存分配。这仍然不能解决引用计数。 解决方案 您可以通过将FData定义为普通PAnsiChar或PByte来修复代码。 使FData像这样: TBuffer = record private FData : PByte; function GetLength: cardinal; function GetType: byte; public class operator implicit(const A: TBytes): TBuffer; class operator implicit(const A: TBuffer): PByte; property Length: cardinal read GetLength; property DataType: byte read GetType; end; 重写CreateThing,如下所示: constructor TThing.CreateThing(const AThingType : Byte; const AThingData: TBytes); begin SetLength(FBuf,Length(AThingData) + Sizeof(AThingType) + 2); FBuf[0] := AThingType; Move(AThingData[0],Length(AThingData)); FBuf[Lengh(FBuf)-1]:= 0; FBuf[Lengh(FBuf)-2]:= 0; //trailing zeros for compatibility with pansichar FData := FBuf; //will call the implicit class operator. end; class operator TBuffer.implicit(const A: TBytes): TBuffer; begin Result.FData:= PByte(@A[1]); end; 我不明白为什么试图超越编译器。 type TMyData = record DataType: byte; Buffer: Ansistring; .... 并与之配合。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- php – Laravel 4:Config get返回数组或null
- leetcode 109. 有序链表转换二叉搜索树(Convert
- [VB.NET]急求解答!怎样读取access中的图片
- perl利用SMTP发送邮件脚本(带认证)
- spring中BeanPostProcessor之三:InitDestroyAnn
- JSK-217 阶乘【大数】
- Delphi 与 DirectX 之 DelphiX(76): TDIB.Ink();
- delphi – 当我释放画布时,DC会发生什么?
- <<BASM 初学者入门>> 第 4 课
- [VB.NET]出错 ExecuteReader: CommandText 属性尚