我正在将基于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;
FPacketBuffe
r是在每个TMyContext类中声明的全局指针,PacketBufferPtr
是在每个TMyContext类中声明的Integer变量我应该在这里使用NativeInt而不是Cardinal吗?这可能是问题的根源吗?如果是,为什么当用户数低于400时没有创建错误,我使用本地环境中的所有函数进行测试,并且没有任何代码部分产生错误。
由于
答案 0 :(得分:4)
64位代码必须了解的是指针是64位宽。与指针为32位宽的32位代码形成对比。现在,本机整数类型Integer
和Cardinal
总是32位宽。显然,您无法在32位类型中容纳所有64位值。
你是正确的,这个代码在64位下被破坏了。将64位指针强制转换为32位整数可能会导致截断。如果地址适合您的32位类型,代码可能会起作用。如果您必须执行此类演员,则需要转为NativeInt
或NativeUInt
。除了更改强制转换之外,您还需要声明任何包含NativeInt
或NativeUInt
指针的变量。
当然,理想情况下,你应该努力避免这种演员阵容。你可以通过不使用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;
现在代码没有强制转换。
我建议您启用自上而下的内存分配作为调试辅助工具。这将消除这种性质的更多错误。