问题描述
我试图弄清楚是否可以使用Delphi中的implicit类运算符初始化包含动态数组的记录(Berlin 10.1 upd 1)附加的程序产生以下输出:
ci iA r1 r2 r3
1 1 1 1 49694764491115752
2 2 2 2 11570520
3 3 3 3 0
4 4 4 4 0
5 5 5 5 0
- TRec 是包含要初始化的动态数组的记录类型。
- ci 是一个常量的整数数组。
- ia 是一个整数的动态数组。 $ b
- r1,r2,r3 是以不同方式初始化的TREC类型的记录。
从输出可以看出,前两个赋值(r1,r2),使用常数按预期工作。编译器接受第三项赋值 r3:= iArray
,但结果被破坏。调试器显示 TREC.Implicit
中的 v
的值已经错误了。
这里出了什么问题?这是可能的吗
程序Project5;
{$ APPTYPE CONSOLE}
{$ R * .res}
类型
TRec = record
iArray:数组UInt64;
类运算符隐式(const v:UInt64的数组):TRec;
结束
{TRec}
类运算符TRec.Implicit(const v:UInt64的数组):TRec;
var
i:integer;
begin
setlength(Result.iArray,Length(v));
for i:= 0 to High(v)do
Result.iArray [i]:= v [i];
结束
const
ciArray:UInt64的数组[0 .. 4] =(1,2,3,4,5);
var
i:integer;
iArray:UInt64的数组;
r1,r2,r3:TRec;
begin
iArray:= [1,2,3,4,5];
r1:= [1,2,3,4,5];
r2:= ciArray;
r3:= iArray;
Writeln('ci iA r1 r1 r3');
for I:= 0 to High(ciArray)do
Writeln(ciArray [i],'',iArray [i],'',r1.iArray [i],'',r2.iArray [i],'',r3.iArray [i]);
readln;
结束。
它也存在于Win64编译器中)。我查看了生成的asm,似乎编译器会为操作员重载产生错误的指令。这就是为什么错误的值最终在操作符重载的数组中。请在质量门户中报告。
为错误结果生成的代码:
Project109.dpr.46:r3:= iArray;
0040B1F2 A1FC044100 mov eax,[$ 004104fc]
0040B1F7 8945E8 mov [ebp- $ 18],eax
0040B1FA 837DE800 cmp dword ptr [ebp- $ 18],$ 00
0040B1FE 740B jz $ 0040b20b
0040B200 8B45E8 mov eax,[ebp- $ 18]
0040B203 83E804子eax,$ 04
0040B206 8B00 mov eax,[eax]
0040B208 8945E8 mov [ebp- $ 18] ,eax
0040B20B 8D4DD8 lea ecx,[ebp- $ 28]
0040B20E 8B55E8 mov edx,[ebp- $ 18]
0040B211 4A dec edx
0040B212 B8FC044100 mov eax,$ 004104fc / /< - 错误一个
0040B217 E87CF5FFFF调用TRec。& op_Implicit
代码相同的方法:
Project109.dpr.47:r3:= TRec.Implicit(iArray);
0040B22F A1FC044100 mov eax,[$ 004104fc]
0040B234 8945E4 mov [ebp- $ 1c],eax
0040B237 837DE400 cmp dword ptr [ebp- $ 1c],$ 00
0040B23B 740B jz $ 0040b248
0040B23D 8B45E4 mov eax,[ebp- $ 1c]
0040B240 83E804子eax,$ 04
0040B243 8B00 mov eax,[eax]
0040B245 8945E4 mov [ebp - $ 1c],eax
0040B248 8D4DD4 lea ecx,[ebp- $ 2c]
0040B24B 8B55E4 mov edx,[ebp- $ 1c]
0040B24E 4A dec edx
0040B24F A1FC044100 mov eax,[$ 004104fc] //< - 正确一个
0040B254 E8CFF5FFFF调用TRec.Implicit
但是,您可以通过为参数类型为 TArray< UInt64>
的Implicit运算符添加另一个重载,然后再将该变量声明为该类型,编译器选择正确的重载(在这种情况下它不会产生错误的代码)。
Bu请注意,只有当您传递类型为 TArray< UInt64>
的变量,并且在您有其他动态数组时调用错误的变量才会起作用的UInt64
,因为Delphis严格类型规则。
更新:此缺陷已在,并在德尔福10.2东京修复。
I'm trying to figure out whether it is possible to initialise a record containing a dynamic array using the "implicit" class operator in Delphi (Berlin 10.1 upd 1)
The attached program produces the following output:
ci iA r1 r2 r3
1 1 1 1 49694764491115752
2 2 2 2 11570520
3 3 3 3 0
4 4 4 4 0
5 5 5 5 0
- TRec is the record type containing a dynamic array that I want to initialise.
- ci is a constant array of integer.
- ia is a dynamic array of integer.
- r1,r2,r3 are records of type TRec which are initialised in different ways.
As you can see from the output, the first two assignments (r1,r2), using constants work as expected. The third assignment r3 := iArray
is accepted by the compiler, but the result is broken. The debugger shows that the value of v
in TRec.Implicit
is already wrong.
What is going wrong here? Is this possible at all?
program Project5;
{$APPTYPE CONSOLE}
{$R *.res}
type
TRec = record
iArray: array of UInt64;
class operator Implicit(const v: array of UInt64): TRec;
end;
{ TRec }
class operator TRec.Implicit(const v: array of UInt64): TRec;
var
i: integer;
begin
setlength(Result.iArray, Length(v));
for i := 0 to High(v) do
Result.iArray[i] := v[i];
end;
const
ciArray: array [0 .. 4] of UInt64 = (1, 2, 3, 4, 5);
var
i : integer;
iArray : array of UInt64;
r1, r2, r3: TRec;
begin
iArray := [1, 2, 3, 4, 5];
r1 := [1, 2, 3, 4, 5];
r2 := ciArray;
r3 := iArray;
Writeln('ci iA r1 r1 r3');
for I := 0 to High(ciArray) do
Writeln(ciArray[i], ' ', iArray[i], ' ', r1.iArray[i], ' ', r2.iArray[i], ' ', r3.iArray[i]);
readln;
end.
Looks like you found a bug with the codegen there (and it also exists in the Win64 Compiler). I looked through the generated asm and it seems the compiler produces a wrong instruction for the operator overload instead. That is why wrong values end up in the array inside the operator overload. Please report this in Quality Portal.
Code generated for the bad result:
Project109.dpr.46: r3 := iArray;
0040B1F2 A1FC044100 mov eax,[$004104fc]
0040B1F7 8945E8 mov [ebp-$18],eax
0040B1FA 837DE800 cmp dword ptr [ebp-$18],$00
0040B1FE 740B jz $0040b20b
0040B200 8B45E8 mov eax,[ebp-$18]
0040B203 83E804 sub eax,$04
0040B206 8B00 mov eax,[eax]
0040B208 8945E8 mov [ebp-$18],eax
0040B20B 8D4DD8 lea ecx,[ebp-$28]
0040B20E 8B55E8 mov edx,[ebp-$18]
0040B211 4A dec edx
0040B212 B8FC044100 mov eax,$004104fc // <-- wrong one
0040B217 E87CF5FFFF call TRec.&op_Implicit
Code for an equal method:
Project109.dpr.47: r3 := TRec.Implicit(iArray);
0040B22F A1FC044100 mov eax,[$004104fc]
0040B234 8945E4 mov [ebp-$1c],eax
0040B237 837DE400 cmp dword ptr [ebp-$1c],$00
0040B23B 740B jz $0040b248
0040B23D 8B45E4 mov eax,[ebp-$1c]
0040B240 83E804 sub eax,$04
0040B243 8B00 mov eax,[eax]
0040B245 8945E4 mov [ebp-$1c],eax
0040B248 8D4DD4 lea ecx,[ebp-$2c]
0040B24B 8B55E4 mov edx,[ebp-$1c]
0040B24E 4A dec edx
0040B24F A1FC044100 mov eax,[$004104fc] // <-- correct one
0040B254 E8CFF5FFFF call TRec.Implicit
However you can avoid this by adding another overload for the Implicit operator with the parameter type TArray<UInt64>
and then also declare your local variable as that type so the compiler choses the correct overload (the one it does not generate wrong code for in this case).
But be aware that this will only work when you pass variables of the type TArray<UInt64>
and call the wrong one when you have any other dynamic array of UInt64
because of Delphis strict type rules.
Update: This defect was reported in RSP-16084 and fixed in Delphi 10.2 Tokyo.
这篇关于初始化包含动态数组的Delphi Record包含“Implicit”类运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!