FR: allow nested fields for that offsetof-like trick that I almost sure already special-cased.
PtrUint(@PRec(nil)^.field)
is the way to get the offset of the field
in the Rec
that is even used by the compiler codebase.
The most notable thing I found about it is that it becomes true constant. (So is it special-cased? Cool.)
However, it works worse for nested fields. The expression PtrUint(@PType(nil)^.container.field)
can still be used in the procedure body, but does not become true constant, as can be observed in the example below on how it fails to compile explicit const declaration and on worse code generated for MyObjFromB_SubOffsetOf
.
type
PBContainer = ^BContainer;
BContainer = record
b: int32;
end;
PMyObj = ^MyObj;
MyObj = record
dummy: int32;
a: int32;
bCtr: BContainer;
end;
const
AOfs = PtrUint(@PMyObj(nil)^.a);
// BOfs = PtrUint(@PMyObj(nil)^.bCtr.b); // does not compile
BOfs = PtrUint(@PMyObj(nil)^.bCtr) + PtrUint(@PBContainer(nil)^.b); // ugly workaround
function MyObjFromA_SubOffsetOf(aPtr: PInt32): PMyObj;
begin
result := pointer(aPtr) - PtrUint(@PMyObj(nil)^.a);
end;
function MyObjFromA_SubConst(aPtr: PInt32): PMyObj;
begin
result := pointer(aPtr) - AOfs;
end;
function MyObjFromB_SubOffsetOf(bPtr: PInt32): PMyObj;
begin
result := pointer(bPtr) - PtrUint(@PMyObj(nil)^.bCtr.b);
end;
function MyObjFromB_SubConst(bPtr: PInt32): PMyObj;
begin
result := pointer(bPtr) - BOfs;
end;
var
mo: MyObj;
begin
writeln('''a'' offset in ''MyObj'': ', AOfs);
writeln('''b'' offset in ''MyObj'': ', BOfs);
writeln('@mo: ', HexStr(@mo));
writeln('@mo recovered from @mo.a by subtracting "offsetof": ', HexStr(MyObjFromA_SubOffsetOf(@mo.a)));
writeln('@mo recovered from @mo.a by subtracting constant: ', HexStr(MyObjFromA_SubConst(@mo.a)));
writeln('@mo recovered from @mo.b by subtracting "offsetof": ', HexStr(MyObjFromB_SubOffsetOf(@mo.bCtr.b)));
writeln('@mo recovered from @mo.b by subtracting constant: ', HexStr(MyObjFromB_SubConst(@mo.bCtr.b)));
end.
'a' offset in 'MyObj': 4
'b' offset in 'MyObj': 8
@mo: 0000000100012010
@mo recovered from @mo.a by subtracting "offsetof": 0000000100012010
@mo recovered from @mo.a by subtracting constant: 0000000100012010
@mo recovered from @mo.b by subtracting "offsetof": 0000000100012010
@mo recovered from @mo.b by subtracting constant: 0000000100012010
MyObjFromA_SubOffsetOf
:
lea rax,[rcx-$04]
ret
MyObjFromA_SubConst
:
lea rax,[rcx-$04]
ret
MyObjFromB_SubOffsetOf
:
mov rax,rcx
mov edx,$00000008
sub rax,rdx
ret
MyObjFromB_SubConst
:
lea rax,[rcx-$08]
ret
Edited by Rika