Soc*_*cob 6 delphi set delphi-2009
首先,我不是一个非常有经验的程序员.我正在使用Delphi 2009并且一直在处理集合,这些集合似乎表现得非常奇怪甚至不一致.我想这可能是我,但以下看起来显然有些不对劲:
unit test;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
test: set of 1..2;
end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
test := [3];
if 3 in test then
Edit1.Text := '3';
end;
end.
Run Code Online (Sandbox Code Playgroud)
如果您运行该程序并单击该按钮,那么,当然,它将在文本字段中显示字符串"3".但是,如果您使用100之类的数字尝试相同的事情,则不会显示任何内容(在我看来应该如此).我错过了什么或者这是某种错误吗?建议将不胜感激!
编辑:到目前为止,我的观察似乎并不孤单.如果有人对此有一些了解,我会很高兴听到这个消息.此外,如果有人使用Delphi 2010(甚至是Delphi XE),如果你能对这个甚至是一般设置行为(例如"test:set of 256..257")进行一些测试,我将不胜感激.有趣的是看看在新版本中是否有任何变化.
Cos*_*und 12
我很好奇地看看生成的已编译代码,我想到了以下关于如何在Delphi 2010中使用集合的内容.它解释了为什么你可以在什么test := [8]
时候做test: set of 1..2
,以及为什么Assert(8 in test)
在之后立即失败.
一个set of byte
具有用于每一个可能的字节值的一个比特,256个比特中的所有32个字节.一个set of 1..2
需要1个字节,但令人惊讶的set of 100..101
还需要一个字节,所以德尔福的编译器是非常聪明的内存分配.在另一方面,set of 7..8
需要2个字节,并根据只包含值的枚举进行设置,0
并101
要求(喘气)13个字节!
测试代码:
TTestEnumeration = (te0=0, te101=101);
TTestEnumeration2 = (tex58=58, tex101=101);
procedure Test;
var A: set of 1..2;
B: set of 7..8;
C: set of 100..101;
D: set of TTestEnumeration;
E: set of TTestEnumeration2;
begin
ShowMessage(IntToStr(SizeOf(A))); // => 1
ShowMessage(IntToStr(SizeOf(B))); // => 2
ShowMessage(IntToStr(SizeOf(C))); // => 1
ShowMessage(IntToStr(SizeOf(D))); // => 13
ShowMessage(IntToStr(SizeOf(E))); // => 6
end;
Run Code Online (Sandbox Code Playgroud)
结论:
set of byte
256个可能的位,32个字节.set of 1..2
它可能只使用第一个字节,所以SizeOf()
返回1.因为set of 100.101
它可能只使用第13个字节,所以SizeOf()
返回1.因为set of 7..8
它可能使用前两个字节,所以我们得到SizeOf()=2
.这是一个特别有趣的情况,因为它向我们显示位不向左或向右移位以优化存储.另一个有趣的例子是set of TTestEnumeration2
:它使用6个字节,即使那些周围有很多不可用的位.测试1,两组,均使用"第一个字节".
procedure Test;
var A: set of 1..2;
B: set of 2..3;
begin
A := [1];
B := [1];
end;
Run Code Online (Sandbox Code Playgroud)
对于那些了解Assembler的人,请亲自查看生成的代码.对于那些不了解汇编程序的人,生成的代码相当于:
begin
A := CompilerGeneratedArray[1];
B := CompilerGeneratedArray[1];
end;
Run Code Online (Sandbox Code Playgroud)
这不是拼写错误,编译器对两个赋值都使用相同的预编译值.CompiledGeneratedArray[1] = 2
.
这是另一个测试:
procedure Test2;
var A: set of 1..2;
B: set of 100..101;
begin
A := [1];
B := [1];
end;
Run Code Online (Sandbox Code Playgroud)
同样,在伪代码中,编译后的代码如下所示:
begin
A := CompilerGeneratedArray1[1];
B := CompilerGeneratedArray2[1];
end;
Run Code Online (Sandbox Code Playgroud)
同样,没有拼写错误:这次编译器为两个赋值使用不同的预编译值.CompilerGeneratedArray1[1]=2
同时CompilerGeneratedArray2[1]=0
; 编译器生成的代码足够智能,不会用无效值覆盖"B"中的位(因为B保存有关位96..103的信息),但它对两个赋值使用非常相似的代码.
set of 1..2
,用1
和测试2
.对于set of 7..8
唯一的测试用7
和8
.我不认为这set
会被打破.它在整个VCL中都很好地服务于它(并且它在我自己的代码中也占有一席之地).set of 1..2
相同行为的set of 0..7
副作用是编译器中先前缺乏优化的副作用.var test: set of 1..2; test := [7]
)中,编译器应该生成错误.我不会将此归类为错误,因为我不认为编译器的行为应该根据"程序员在错误代码上做什么"来定义,而是根据"程序员如何处理好代码" "; 尽管如此,编译器应该生成的内容Constant expression violates subrange bounds
正如您尝试此代码时所做的那样:(代码示例)
procedure Test;
var t: 1..2;
begin
t := 3;
end;
Run Code Online (Sandbox Code Playgroud)
{$R+}
,错误的赋值应该引发错误,就像尝试此代码时一样:(代码示例)
procedure Test;
var t: 1..2;
i: Integer;
begin
{$R+}
for i:=1 to 3 do
t := i;
{$R-}
end;
Run Code Online (Sandbox Code Playgroud)