一套内存布局

时间:2011-06-06 12:39:23

标签: delphi casting set delphi-2009

如何在Delphi的内存中组织set

我尝试做的是将简单类型转换为类似

的集合类型
var
  MyNumber : Word;
  ShiftState : TShiftState;
begin
  MyNumber:=42;
  ShiftState:=TShiftState(MyNumber);
end;
德尔福(2009)不允许这样做,我不明白为什么。如果我得到一个数字,其中单个位编码不同的枚举值,我会像这样投射它,这将使我的生活更轻松。可以这样做吗?

我要采用的一种方法是:

var
  ShiftState : TShiftState;
  MyNumber : Word absolute ShiftState;
begin
  MyNumber:=42;
end;

但在此之前,我认为我会要求内存布局。这是一种感觉,而不是知道我现在对此的看法。

4 个答案:

答案 0 :(得分:6)

Delphi集是一个位字段,其位对应于集合中元素的关联值。对于一组常规枚举类型,位布局是直截了当的:

  • 位0对应于序数值为0
  • 的set元素
  • 位1对应于序数值为1的集合元素
  • 等等。

当你处理一个非连续的集合或者一个不是从0开始的集合时,事情变得有趣。你可以使用Delphi的子范围类型(​​例如:set of 3..7)或使用枚举类型,指定元素的实际序数值:

type enum=(seven=7, eight=8, eleven=11); 
EnumSet = set of enum;

在这种情况下,Delphi将分配包含所有必需位的最小所需字节数,但不会“移位”位值以使用更少的空间。在EnumSet示例中,Delphi将使用两个字节:

  • 第一个字节的第7位与seven
  • 相关联
  • 第二个字节的位0将与eight
  • 相关联
  • 第二个字节的第3位与eleven
  • 相关联

你可以在这里看到我做过的一些测试:Delphi 2009 - Bug? Adding supposedly invalid values to a set

使用Delphi 2010进行测试,没有为Delphi XE重复测试。

答案 1 :(得分:1)

您必须选择正确大小的序数类型。对我来说(D2007),您的代码会使用MyNumber: Byte编译:

procedure Test;
var
  MyNumber: Byte;
  ShiftState: TShiftState;
begin
  MyNumber := 42;
  ShiftState := TShiftState(MyNumber);
end;

我在某些情况下使用过这种技术,并没有遇到问题。


<强>更新

自Delphi 2010以来TShiftState类型已经扩展到包括两个新状态ssTouchssPen,基于corresponding doc pagecurrent doc page)。 Delphi 2009 doc仍然将TShiftState定义为一组7个州。

因此,您尝试将Word转换为TShiftState将在Delphi 2010 +中有效,但Byte适用于Delphi 2009。

答案 2 :(得分:1)

不幸的是,我刚才偶然发现了以下问题:Delphi 2009 - Bug? Adding supposedly invalid values to a set

Cosmin接受的答案包含对Delphi中集合的详细描述。为什么我最好不要使用absolute的方法。显然,set变量可以占用1到32个字节的内存,具体取决于枚举值。

答案 3 :(得分:0)

我用这个:

对于&lt; = 8个元素,PByte(@MyNumber)^,对于&lt; = 16个元素,PWord(@MyNumber)^等

如果枚举占用更多空间(通过最小枚举大小编译器选项),这仍然有用。