Delphi程序带有字符串参数

在Delphi中处理程序和字符串时遇到问题.事实上,我预计会看到输出字符串“1S2S3S4S5S6S”,但实际输出为“1234S5S6”.在调试过程中,它说S1,S2,S3和S6字符串变量没有被初始化(S1,S3,S6是“串”,S4和S5有值“S”).有人可以向我解释一下吗以下是代码
program StringTest;

{$APPTYPE CONSOLE}

procedure MyProcedure(S1: String; const S2: String; var S3: String;
                      S4: String; const S5: String; var S6: String;
                      out S7: String);
begin
  S7 := '1' + S1 + '2' + S2 + '3' + S3 + '4' + S4 + '5' + S5 + '6' + S6;
end;

procedure Work;
var
  S: String;
begin
  S := 'S';
  MyProcedure(S,S,S);
  writeln(S);
end;

begin
  Work;
  readln;
end.

解决方法

您的S7参数被声明为out参数,因此编译器将在调用函数时将传递的变量设置为空字符串.您正在为所有参数传递相同的S变量,包括输出参数,所以在函数内部使用参数值之前,S的值将从内存中擦除.

要进一步阐述,程序正在使用寄存器调用约定,其中S1..S3分别在cpu寄存器(EAX,EDX和ECX)中传递,而S4..S6则传递给堆栈.输入字符串变量在其当前值被推送到堆栈S4和S5(S3和S6只是指向变量的指针)之后,并且该值被分配给S1和S2之前被清除.所以,S1和S2结束为零,S4和S5在擦除之前包含指向原始“S”数据的指针,S3和S6指向被擦除的字符串变量.

调试器可以显示所有这些操作.如果在调用MyProcedure()的行上放置断点,然后打开cpu视图,您将看到以下装配说明:

StringTest.dpr.17: MyProcedure(S,S);
00405A6C 8B45FC           mov eax,[ebp-$04]  // [ebp-$04] is the current value of S
00405A6F 50               push eax           // <-- assign S4
00405A70 8B45FC           mov eax,[ebp-$04]
00405A73 50               push eax           // <-- assign S5
00405A74 8D45FC           lea eax,[ebp-$04]
00405A77 50               push eax           // <-- assign S6
00405A78 8D45FC           lea eax,[ebp-$04]
00405A7B E8B0EDFFFF       call @UStrClr      // <-- 'out' wipes out S!
00405A80 50               push eax           // <-- assign S7
00405A81 8D4DFC           lea ecx,[ebp-$04]  // <-- assign S3
00405A84 8B55FC           mov edx,[ebp-$04]  // <-- assign S2
00405A87 8B45FC           mov eax,[ebp-$04]  // <-- assign S1
00405A8A E8B9FEFFFF       call MyProcedure

解决这个问题,你需要使用一个不同的变量来接收输出

procedure Work;
var
  S,Res: String;
begin
  S := 'S';
  Proc(S,Res);
  WriteLn(Res);
end;

或者,将过程更改为通过其Result而不是使用out参数返回新String的函数

function MyFunction(S1: String; const S2: String; var S3: String;
                      S4: String; const S5: String; var S6: String): String;
begin
  Result := '1' + S1 + '2' + S2 + '3' + S3 + '4' + S4 + '5' + S5 + '6' + S6;
end;

procedure Work;
var
  S: String;
begin
  S := 'S';
  WriteLn(MyFunction(S,S));
end;

相关文章

 从网上看到《Delphi API HOOK完全说明》这篇文章,基本上都...
  从网上看到《Delphi API HOOK完全说明》这篇文章,基本上...
ffmpeg 是一套强大的开源的多媒体库 一般都是用 c/c+&#x...
32位CPU所含有的寄存器有:4个数据寄存器(EAX、EBX、ECX和ED...
1 mov dst, src dst是目的操作数,src是源操作数,指令实现的...