Get Position of a struct var AKA Offset of record

2019-02-15 02:36发布

问题:

I would like to get a "position" of a structure/record.

Say I have this record:

type
  MyStruct = record
    MyInteger   : Integer;
    MyInteger2  : Integer;
    MyInteger3  : Integer;
    MyFunc      : function (FirstParam : WideString; SecondParam : String) : Integer;
    MyString    : String;
    MyString2   : WideString;
    MyPchar     : pchar;
end;

As you can see this record has a size of 28 bytes (7 vars x 4 bytes). Basically because all the vars are either 4 byte vars (such as Integer) or pointers (also 4 bytes). Now let's say we have this struct loaded in an memory-address (X = 0) (which also means the address for MyInteger would be 0). The address of MyInteger3 (for example) would be 8 (be aware of the X = 0 !) How can I get the position (number/address) of the struct dynamically?

Hope you guys know what I mean? Thanks in advance.

BTW: Is any Var always 4 bytes in a struct? EDIT: This is wrong if you fix the spcae : String[100]

回答1:

You can get the offset of any record member using some pointer arithmetic:

type
  PMyStruct = ^MyStruct;

var
  Offset: Integer;
begin
  Offset := Integer(@(PMyStruct(nil).MyInteger3));
  // or:
  // Offset := Integer(Addr(PMyStruct(nil).MyInteger3));
end;

If you want the offset of the function you need to code it like this:

Offset := Integer(@@PMyStruct(nil).MyFunc);
// or:
// Offset := Integer(Addr(@PMyStruct(nil).MyFunc));


回答2:

program OffsetTest; {$APPTYPE CONSOLE}

type
  f = function (FirstParam : WideString; SecondParam : String) : Integer;
  TStruct = record
    MyInteger   : Integer;
    MyInteger2  : Integer;
    MyInteger3  : Integer;
    MyFunc      : ^f;
    MyString    : String;
    MyString2   : WideString;
    MyPchar     : pchar;
  end;

var MyStruct :TStruct;

begin
  Writeln( int64(@(MyStruct.MyInteger )) - int64(@(MyStruct)));
  Writeln( int64(@(MyStruct.MyInteger2)) - int64(@(MyStruct)));
  Writeln( int64(@(MyStruct.MyInteger3)) - int64(@(MyStruct)));
  Writeln( int64(@(MyStruct.MyFunc    )) - int64(@(MyStruct)));
  Writeln( int64(@(MyStruct.MyString2 )) - int64(@(MyStruct)));
  Writeln( int64(@(MyStruct.MyPchar   )) - int64(@(MyStruct)));
  Readln;
end.

Results with 32bits version:

0 
4 
8
12
20
24

Results with 64bits version:

0
4
8
16
32
40

Results with 64bits, packed record:

0
4
8
12
28
36

Showing the different results to point out that it might be a bad idea to rely on these offsets in your code. Or at least be very aware that different circumstances might result in different offsets.