4

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]

Arioch 'The
  • 15,799
  • 35
  • 62
Ben
  • 3,380
  • 2
  • 44
  • 98
  • 7
    No, variables in a struct are not always 4 bytes (thing types smaller than 4 bytes, like Word, Byte, Boolean, enums, etc), and are not always aligned on 4-byte memory boundaries (packed records, Word-aligned or Int64-aligned records, etc). And Pointers are 8 bytes on 64-bit systems. – Remy Lebeau Nov 01 '12 at 02:32
  • 1
    @Remy - you also not mentioned compiler directives, that may change alignment to 1,2,4 or 8 bytes boundary at developer's option – Arioch 'The Nov 01 '12 at 08:01

2 Answers2

10

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));
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
7
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.

Wouter van Nifterick
  • 23,603
  • 7
  • 78
  • 122