【问题标题】:Delphi 7 to Delphi XE5德尔福 7 到德尔福 XE5
【发布时间】:2014-07-08 07:30:52
【问题描述】:

我正在将基于 Indy TCP 组件的服务器从 Delphi 7 移植到 XE5 以启用 64 位支持。现在,在我完成所有移植并运行服务器之后,它在测试环境中运行良好。在用户数超过 400 之前它一直运行良好。之后它开始创建访问冲突错误。有时打破错误将我指向 indy 源文件,有时指向 CPU 窗口。我无法在我的源代码中查明产生错误的代码区域。

虽然这种访问冲突错误意味着我正在访问一些尚未实例化的对象,但是为什么当较少的用户在线并且整个代码与Delphi 7代码完全相同时不会产生错误,对象被访问并以与我在 Delphi 7 中相同的方式释放。

我在某处读到,与转换指针相关的东西应该使用 NativeInt 而不是 Integer/Cardinal,现在在我处理传入数据的代码中,代码如下所示

procedure TMyContext.AddToPacketBuffer(Buffer: Pointer; Size: Integer);
var
  DestPtr: Pointer;
begin
  if PacketBufferPtr + Size<65536 then
  begin
    DestPtr := Pointer(Cardinal(FPacketBuffer)+Cardinal(PacketBufferPtr));
    Move(Buffer^,DestPtr^,Size);
    PacketBufferPtr := PacketBufferPtr + Size;
  end
  else
  begin
  end;
end;
  • FPacketBuffer 是每个 TMyContext 类中声明的全局指针,PacketBufferPtr 是每个 TMyContext 类中声明的 Integer 变量

我应该在这里使用 NativeInt 而不是 Cardinal?这可能是问题的根源吗?如果是,为什么当用户数低于 400 时它不会产生错误,我在本地环境中使用所有功能进行了测试,并且没有单个代码部分产生错误。

谢谢

【问题讨论】:

  • 我回滚了您的编辑。你真的需要问一个新问题。这是个好问题。简洁明了。您的编辑提出了一个新问题。随意提出一个新问题。
  • 是的,我在提交编辑后意识到:)

标签: delphi delphi-7 delphi-xe5


【解决方案1】:

关于 64 位代码,您必须了解的是指针是 64 位宽的。与指针为 32 位宽的 32 位代码不同。现在,本机整数类型 IntegerCardinal 始终为 32 位宽。显然,您不能将所有 64 位值都放入 32 位类型中。

您是正确的,此代码在 64 位下被破坏。将 64 位指针转换为 32 位整数可能会导致截断。如果地址适合您的 32 位类型,则该代码可能有效。如果您必须执行这样的转换,那么您需要转换为NativeIntNativeUInt。除了更改强制转换之外,您还需要将任何持有指针的变量声明为 NativeIntNativeUInt

当然,理想情况下,您应该努力完全避免此类强制转换。您可以通过不使用Integer 变量来存储指针来做到这一点。将指针存储为指针,避免转换为整数并且永远不会遇到指针截断错误。

也就是说,PacketBufferPtr 的名称非常具有误导性。它不是顾名思义的指针。这是一个偏移量。它应该命名为PacketBufferOffset。它永远不会超过high(Integer) 似乎是合理的,因此Integer 可能是一个合理的选择。但是将其声明为NativeUInt 永远不会有什么坏处。

因此,假设您将指针声明为PByte,并将偏移量声明为NativeUInt,那么代码将这样编写:

var
  FPacketBuffer: PByte;
  PacketBufferOffset: NativeUInt;
....    
procedure TMyContext.AddToPacketBuffer(Buffer: Pointer; Size: Integer);
var
  DestPtr: PByte;
begin
  if PacketBufferOffset + Size<65536 then
  begin
    DestPtr := FPacketBuffer + PacketBufferOffset;
    Move(Buffer^, DestPtr^, Size);
    inc(PacketBufferOffset, Size);
  end
  else
  begin
  end;
end;

现在代码没有强制转换了。

我建议您启用自上而下的内存分配作为调试辅助。这将清除更多这种性质的错误。

【讨论】:

  • 谢谢,我实际上需要这种内存操作,因为接收到的数据需要存储在全局内存中,我需要跟踪以前存储在其中的数据以及在哪里添加更多分配的内存空间中的数据......所以我应该将它们类型转换为 NativeInt 而不是 Cardinal,以及如何启用自上而下的内存分配。
  • 此处自上而下的内存分配详细信息:msdn.microsoft.com/en-us/library/bb190527.aspx 尽管启用此设置时如果您的 AV 软件卡顿也不要感到惊讶
  • 我会将指针变量声明为指针。但是名为PacketBufferPtr 的变量不是指针。这是一个偏移量。我已经更新了答案,说明如何在没有强制转换的情况下编写它。
  • 感谢所有的帮助,我做了一些更改,还有一些我很困惑的地方,请您查一下。我还不能在现场测试它,像往常一样,它永远不会在我的测试环境中造成任何问题
  • 对不起,我不想调试整个程序。我真的认为我回答了你的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-11
  • 1970-01-01
相关资源
最近更新 更多