@H_403_1@我正在寻找在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的记录,那么你有更大的问题!