Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get Position of a struct var AKA Offset of record field

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]

like image 685
Ben Avatar asked Dec 04 '22 14:12

Ben


2 Answers

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));
like image 68
Remy Lebeau Avatar answered Jan 01 '23 17:01

Remy Lebeau


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.

like image 32
Wouter van Nifterick Avatar answered Jan 01 '23 16:01

Wouter van Nifterick