Skip to content

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
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information