Initialisation de L'enregistrement Delphi contenant un tableau dynamique avec un opérateur de classe 'implicite'
J'essaie de comprendre s'il est possible d'initialiser un enregistrement contenant un tableau dynamique en utilisant l'opérateur de classe "implicite" dans Delphi (Berlin 10.1 upd 1)
Le programme joint produit la sortie suivante:
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 est le type d'enregistrement contenant un tableau dynamique que je veux initialiser.
- ic est une constante tableau d'entiers.
- ia est un tableau dynamique de entier.
- r1, r2, r3 sont des enregistrements de type TRec qui sont initialisés de différentes manières.
Comme vous pouvez le voir à partir de la sortie, les deux premières affectations (r1,r2), en utilisant des constantes fonctionnent comme prévu. La troisième affectation r3 := iArray
est acceptée par le compilateur, mais le résultat est cassé. Le débogueur montre que la valeur de v
dans TRec.Implicit
est déjà mal.
Qu'est-ce qui ne va pas ici? Est-ce possible?
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.
1 réponses
On dirait que vous avez trouvé un bug avec le codegen (et il existe également dans le compilateur Win64). J'ai regardé à travers l'asm généré et il semble que le compilateur produise une mauvaise instruction pour la surcharge de l'opérateur à la place. C'est pourquoi les mauvaises valeurs se retrouvent dans le tableau à l'intérieur de la surcharge de l'opérateur. Veuillez le signaler dans Quality Portal.
Code généré pour le mauvais résultat:
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 pour une méthode égale:
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
Cependant, vous pouvez éviter cela en ajoutant un autre surcharge pour l'opérateur implicite avec le type de paramètre TArray<UInt64>
, puis déclare également votre variable locale comme ce type afin que le compilateur choisisse la surcharge correcte (celle pour laquelle il ne génère pas de code erroné dans ce cas).
Mais sachez que cela ne fonctionnera que lorsque vous transmettez des variables du type TArray<UInt64>
et appelez la mauvaise lorsque vous avez d'autres array of UInt64
dynamiques à cause des règles de type strictes de Delphis.
Mise à Jour: Ce défaut a été signalé dans RSP-16084 et fixé à Delphi 10.2 Tokyo.