如何在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;
但在此之前,我认为我会要求内存布局。这是一种感觉,而不是知道我现在对此的看法。
答案 0 :(得分:6)
Delphi集是一个位字段,其位对应于集合中元素的关联值。对于一组常规枚举类型,位布局是直截了当的:
当你处理一个非连续的集合或者一个不是从0开始的集合时,事情变得有趣。你可以使用Delphi的子范围类型(例如:set of 3..7
)或使用枚举类型,指定元素的实际序数值:
type enum=(seven=7, eight=8, eleven=11);
EnumSet = set of enum;
在这种情况下,Delphi将分配包含所有必需位的最小所需字节数,但不会“移位”位值以使用更少的空间。在EnumSet
示例中,Delphi将使用两个字节:
seven
eight
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
类型已经扩展到包括两个新状态ssTouch
和ssPen
,基于corresponding doc page(current 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)^等
如果枚举占用更多空间(通过最小枚举大小编译器选项),这仍然有用。