【问题标题】:Get Position of a struct var AKA Offset of record field获取记录字段的结构 var AKA 偏移量的位置
【发布时间】:2012-10-31 23:38:11
【问题描述】:

我想获得结构/记录的“位置”。

假设我有这个记录:

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

如您所见,这条记录的大小为 28 字节(7 vars x 4 字节)。基本上是因为所有变量都是 4 字节变量(例如整数)或指针(也是 4 字节)。 现在假设我们将这个结构加载到内存地址 (X = 0) 中(这也意味着 MyInteger 的地址将为 0)。 MyInteger3 的地址(例如)将是 8 (注意 X = 0 !) 如何动态获取结构的位置(编号/地址)?

希望你们明白我的意思吗? 提前致谢。

顺便说一句: 结构中的任何 Var 总是 4 个字节吗? 编辑: 如果您修复 spcae,这是错误的:String[100]

【问题讨论】:

  • 不,结构中的变量并不总是 4 字节(小于 4 字节的事物类型,如 Word、Byte、Boolean、枚举等),并且并不总是在 4 字节内存边界上对齐(打包的记录、字对齐或 Int64 对齐的记录等)。在 64 位系统上,指针是 8 个字节。
  • @Remy - 你也没有提到编译器指令,开发者可以选择将对齐更改为 1、2、4 或 8 字节边界

标签: delphi memory-management struct delphi-7 record


【解决方案1】:

您可以使用一些指针算法来获取任何记录成员的偏移量:

type
  PMyStruct = ^MyStruct;

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

如果你想要函数的偏移量,你需要这样编码:

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

【讨论】:

  • 太棒了!这就是我要找的!非常感谢!
  • 请注意,这不适用于该功能。请参阅我的示例,了解如何解决此问题。
  • 编译器是否接受这样的表达式作为常量?
  • @WoutervanNifterick 你可以很容易地做到这一点,Remy 的实例免费方式太容易了。查看我的更新。
  • 如果您的编译器版本是 Delphi-2006 或更高版本,您可以在 MyStruct 中添加类函数:class function MyInteger3Offs : Integer; static; 和实现:class function MyStruct.MyInteger3Offs: Integer; begin Result := Integer(@(PMyStruct(nil).MyInteger3)); end;
【解决方案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.

32 位版本的结果:

0 
4 
8
12
20
24

64 位版本的结果:

0
4
8
16
32
40

64 位结果,打包记录:

0
4
8
12
28
36

显示不同的结果以指出在代码中依赖这些偏移量可能是个坏主意。或者至少要非常清楚不同的情况可能会导致不同的偏移量。

【讨论】:

  • 这同样适用!一个非常小的缺点是你必须分配一个结构。
  • +1,也用于指出不同对齐方式的缺陷。
猜你喜欢
  • 2013-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-27
  • 1970-01-01
  • 2011-03-06
  • 2020-03-16
  • 2011-01-03
相关资源
最近更新 更多