我正在寻找一种获得Delphi记录中字段偏移量的方法。以下两种方法可以工作,但我希望有更简洁的方式。基本上,我希望第三个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:看起来这是一个之前已有的问题的重复:之前相似的问题 正如RRUZ所指出的那样。 如在那里所示,另一种方法是声明一个全局变量并按如下方式使用它。 奇怪的是编译器仍然无法在编译时分配正确的值,正如汇编输出中所示,因此为了效率和可读性,最好使用空值方法。
---- var ----
---- rec_a_ofs:rec_a; ----
---- ... ----
---- result:=longint(@rec_a_ofs.c)-longint(@rec_a_ofs); ----
mov eax,$0045f5d8
sub eax,$0045f5d0
编辑3:好的,用所有已知的方法修改了代码。请注意,生成的汇编代码对于第三种、第四种和第五种(类方法)方式是相同的,无论它们是否被内联。当你开始做这些事情时,请选择你喜欢的方式!
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;