在Delphi中将一个记录指针分配给一个字符数组-再来?

在Delphi中将一个记录指针分配给一个字符数组-再来?,delphi,Delphi,我最近开始做一个Delphi项目,发现了一段非常奇怪的代码 // Type declarations type TDataSet = record VolumeLevel : char; DeviceMasks : char; DeviceList: array [1..MAX] of array [1..8] of char; DisplayList: array [1..MAX] of array [1..8] of char; end; type

我最近开始做一个Delphi项目,发现了一段非常奇怪的代码

// Type declarations

type
    TDataSet = record
    VolumeLevel : char;
    DeviceMasks : char;
    DeviceList: array [1..MAX] of array [1..8] of char;
    DisplayList: array [1..MAX] of array [1..8] of char;
end;

type
    TSerialPacket = record
    Preamble: array[1..4] of byte;
    PacketType: byte;
    PacketLen: byte;
    Data: array of char;
    Checksum: byte;
end;

...

// Private fields

Packet  : TSerialPacket;
DataSet : TDataSet;

...

// Actual procedure

SetLength(Packet.Data, sizeof(DataSet));
Packet.Data := @DataSet;
我很少使用Delphi,所以这段代码对我来说似乎不可理解。编译器认为这没问题,我可以运行代码。我用调试器运行了它,但Packet.Data的值似乎没有改变。谁能告诉我这是干什么的?将自定义记录的指针指定给字符数组似乎很奇怪

此外,由于某些原因,SetLength会触发一个错误:Project Foo.exe引发了异常类EAccessViolation,消息为“模块'Foo.exe'中地址00403860处的访问冲突”。读取地址00000000。。在工作和崩溃运行期间,数据包的值为,数据集的大小为260。我还没能确定到底发生了什么变化。据我所知,SetLength不应该依赖于Packet.Data和DataSet以外的任何其他变量

我在Windows 7上使用Delphi XE。

我猜最后一行是

Packet.Data := @DataSet;
宁可

Move(DataSet, Packet.Data[0], SizeOf(DataSet));
我猜最后一行

Packet.Data := @DataSet;
宁可

Move(DataSet, Packet.Data[0], SizeOf(DataSet));

我想我知道你的代码出了什么问题

如前所述,这相当糟糕:

SetLength(Packet.Data, sizeof(DataSet)); 
Packet.Data := @DataSet; 
我假设你的代码只会在第二次运行SetLength时崩溃。 发生的是

Packet.Data := @DataSet;
这里,Char指针数组被Dataset变量的地址替换。然后释放由Setlength创建的字符数组

当您第二次访问SetLength时,编译器认为指向Char数组的指针实际上是指向TDataset的指针。这类似于打电话

SetLength(@Dataset, SizeOf(Dataset));
只是编译器不允许这样


我希望这有助于发现您遇到的任何其他问题。

我想我知道您的代码出了什么问题

如前所述,这相当糟糕:

SetLength(Packet.Data, sizeof(DataSet)); 
Packet.Data := @DataSet; 
我假设你的代码只会在第二次运行SetLength时崩溃。 发生的是

Packet.Data := @DataSet;
这里,Char指针数组被Dataset变量的地址替换。然后释放由Setlength创建的字符数组

当您第二次访问SetLength时,编译器认为指向Char数组的指针实际上是指向TDataset的指针。这类似于打电话

SetLength(@Dataset, SizeOf(Dataset));
只是编译器不允许这样


我希望这有助于发现您遇到的任何其他问题。

FWIW:D2007我得到了[DCC Fehler]项目1.dpr35:E2010 InCompatible Typen:“动态数组”和“指针”,正如我快速查看代码所期望的那样。奇怪。对于Packet.Data:=数据集,我遇到了一个错误:类型不兼容:“dynamic array”和TDataSet。但是Packet.Data:=@DataSet是可以的。啊,这是罪过。我已经更改了默认编译器选项,将{$TYPEDADDRESS ON}包括在内,这就解释了区别。但根据您目前的经验,您可能也应该将其包括在内:-是的,我可能应该。一旦软件正常工作,我将打开所有警告级别并修复问题。不幸的是,前几位作者似乎只修复了错误,没有注意到所有的警告。我认识那种开发人员-FWIW:通过D2007,我得到了[DCC Fehler]项目1.dpr35:E2010 InCompatible Typen:“动态数组”和“指针”,正如我快速查看代码所期望的那样。奇怪。对于Packet.Data:=数据集,我遇到了一个错误:类型不兼容:“dynamic array”和TDataSet。但是Packet.Data:=@DataSet是可以的。啊,这是罪过。我已经更改了默认编译器选项,将{$TYPEDADDRESS ON}包括在内,这就解释了区别。但根据您目前的经验,您可能也应该将其包括在内:-是的,我可能应该。一旦软件正常工作,我将打开所有警告级别并修复问题。不幸的是,前几位作者似乎只修复了错误,没有注意到所有的警告。我认识那种开发人员-这两者有什么区别?上面的一个是某种不推荐的方式,还是一直以来都是一个丑陋的黑客行为?AFAICS的指针分配是一个错误。我不相信它能在比您的测试样本稍微复杂的代码中可靠地工作。如上所述,我建议任何人将$TYPEDADDRESS设置为ON。然后编译器会帮你检测到这种错误。虽然这并没有解决我的整个问题,但它为我指明了前进的方向,所以我将它标记为已接受。考虑到上面有限的代码示例,我甚至不知道这个问题是否可以解决。当我解决这个问题时,我会回到这个问题上来。@Ville,你在问题中提到的技术一直都是错误的,而且总是容易出现内存损坏和无效指针操作异常。不管是谁写的代码都没有思考。它设置数组的长度,然后通过为变量指定一个新值来丢弃该数组。新值不是动态数组。它可能看起来有点类似于动态数组,但任何尝试使用它的行为都会导致
ld失败,因为新值不包括真实动态数组所需的动态数组簿记。这两者之间有什么区别?上面的一个是某种不推荐的方式,还是一直以来都是一个丑陋的黑客行为?AFAICS的指针分配是一个错误。我不相信它能在比您的测试样本稍微复杂的代码中可靠地工作。如上所述,我建议任何人将$TYPEDADDRESS设置为ON。然后编译器会帮你检测到这种错误。虽然这并没有解决我的整个问题,但它为我指明了前进的方向,所以我将它标记为已接受。考虑到上面有限的代码示例,我甚至不知道这个问题是否可以解决。当我解决这个问题时,我会回到这个问题上来。@Ville,你在问题中提到的技术一直都是错误的,而且总是容易出现内存损坏和无效指针操作异常。不管是谁写的代码都没有思考。它设置数组的长度,然后通过为变量指定一个新值来丢弃该数组。新值不是动态数组。它可能看起来有点类似于动态数组,但任何尝试使用它的尝试都可能失败,因为新值不包括真实动态数组所需的动态数组簿记。这解决了问题,所以我接受这个而不是Ulrich的答案。这解决了问题,所以我接受这个而不是Ulrich的答案。