微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

德尔福:记录领域的偏移

我正在寻找在Delphi记录中获取字段偏移的方法.以下2种方法有效,但我希望能够更清洁.基本上我会喜欢第三次showmessage工作.有任何想法吗?
type
 rec_a=record
  a:longint;
  b:byte;
  c:pointer;
 end;

{$warnings off}
function get_ofs1:longint;
var
 abc:^rec_a;
begin
 result:=longint(@abc.c)-longint(abc);
end;
{$warnings on}

function get_ofs2:longint;
asm
 mov eax,offset rec_a.c
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 showmessage(inttostr(get_ofs1));
 showmessage(inttostr(get_ofs2));
// showmessage(inttostr(longint(addr(rec_a.c)))); // is there a way to make this one work?
end;

编辑:
好的,下面的答案很好,谢谢!作为参考,以下是各种选项的汇编器输出

---- result:=longint(@abc.c)-longint(abc); ----
lea edx,[eax+$08]
sub edx,eax
mov eax,edx

---- mov eax,offset rec_a.c ----
mov eax,$00000008

---- result:=longint(@rec_a(nil^).c); ----
xor eax,eax
add eax,$08

编辑2:看起来像以前的问题的复制:previous similar question,如RRUZ所述.如图所示,另一种方法是声明一个全局变量并使用它,如下所示.奇怪的是,编译器仍然无法在编译时分配正确的值,如汇编器输出中所见,因此对于效率和可读性,最好使用nil方法.

---- var ----
----  rec_a_ofs:rec_a; ----
---- ... ----
---- result:=longint(@rec_a_ofs.c)-longint(@rec_a_ofs); ----
mov eax,$0045f5d8
sub eax,$0045f5d0

edit3:好的修改代码,所有知道的方式来完成这个.请注意,第3,第4和第5(类方法)方式生成的汇编代码是否相同,无论是否内联.选择你最喜欢的方式,当你做这些东西!

type
 prec_a=^rec_a;
 rec_a=record
  a:longint;
  b:byte;
  c:pointer;

  class function offset_c:longint;static;inline;
 end;

//const
// rec_a_field_c_offset=longint(@rec_a(nil^).c); // no kNown way to make this work

{$warnings off}
function get_ofs1:longint;inline;
var
 abc:^rec_a;
begin
 result:=longint(@abc.c)-longint(abc);
end;
{$warnings on}

function get_ofs2:longint;
asm
 mov eax,offset rec_a.c
end;

function get_ofs3:longint;inline;
begin
 result:=longint(@rec_a(nil^).c);
end;

function get_ofs4:longint;inline;
begin
 result:=longint(@prec_a(nil).c);
end;

class function rec_a.offset_c:longint;
begin
 result:=longint(@prec_a(nil).c);
end;

var
 rec_a_ofs:rec_a;

function get_ofs6:longint;inline;
begin
 result:=longint(@rec_a_ofs.c)-longint(@rec_a_ofs);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 showmessage(inttostr(get_ofs1));
 showmessage(inttostr(get_ofs2));
 showmessage(inttostr(get_ofs3));
 showmessage(inttostr(get_ofs4));
 showmessage(inttostr(rec_a.offset_c));
 showmessage(inttostr(get_ofs6));
// showmessage(inttostr(rec_a_field_c_offset));
end;

解决方法

我总是用这种方法
Offset := Integer(@rec_a(nil^).c);

不要让使用nil ^把你关掉,这是完全安全的.而不用担心64位指针截断.如果你有一个大小为> 4GB的记录,那么你有更大的问题!

原文地址:https://www.jb51.cc/delphi/102816.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐