Delphi: Offset of record field

前端 未结 2 1938
小蘑菇
小蘑菇 2020-12-11 14:53

I\'m looking for ways to obtain the offset of a field in a Delphi record. These 2 following methods work but i was hoping for a cleaner way. Basically i would have liked the

相关标签:
2条回答
  • 2020-12-11 15:42

    I always use this approach:

    Offset := Integer(@rec_a(nil^).c);
    

    Don't let the use of nil^ put you off, it's perfectly safe. And don't worry about 64 bit pointer truncation. If you have a record whose size is >4GB then you have bigger problems!

    0 讨论(0)
  • 2020-12-11 15:46

    You could also use a generic approach:

    uses
      System.SysUtils,TypInfo,RTTI;
    
    function GetFieldOffset( ARecordTypeInfo : PTypeInfo;
                             const ARecordFieldName : String) : Integer;
    var
      MyContext: TRttiContext;
      MyField: TRttiField;
    begin
      if (ARecordTypeInfo.Kind <> tkRecord) then
        raise Exception.Create('Not a record type');
      for MyField in MyContext.GetType(ARecordTypeInfo).GetFields do
        if MyField.Name = ARecordFieldName then
        begin
          Exit(MyField.Offset);
        end;
      raise Exception.Create('No such field name:'+ARecordFieldName);
    end;
    

    And call it like this:

    ShowMessage( IntToString( GetFieldOffset( TypeInfo(rec_a),'c')));
    

    Not as fast as your other alternatives, but gives a unified generic solution.


    Looking at your options here for a clean solution, it seems the best is to declare a generic function:

    function GetFieldOffset( const P : Pointer) : Integer; Inline;
    // Example calls :
    //   GetFieldOffset( @PMyStruct(nil).MyParameter);
    //   GetFieldOffset( @TMyStruct(nil^).MyParameter);
    begin
      Result := Integer( P);
    end;
    

    So even if the call looks awkward, the function name tells you what's going on. Inlining the call removes the function call overhead, so it will work as a code beautifier.

    It is possible to get constant values for a record base and field address:

    const
      cStruct : MyStruct = ();
      cMyInteger3Offs : Pointer = @cStruct.MyInteger3;
      cMyStructBase   : Pointer = @cStruct;
    

    But this will not make code look cleaner.

    0 讨论(0)
提交回复
热议问题