带字符串参数的 Delphi 程序

标签 delphi delphi-7

我在 Delphi 中处理过程和字符串时遇到问题。事实上,我期望看到输出字符串“1S2S3S4S5S6S”,但实际输出是“1234S5S6”。在调试过程中,它表示 S1、S2、S3 和 S6 字符串变量未初始化(S1、S2、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, S, S, S, S);
  writeln(S);
end;

begin
  Work;
  readln;
end.

最佳答案

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

为了进一步详细说明,该过程使用 register 调用约定,其中 S1..S3 在 CPU 寄存器(EAX、分别是 EDX 和 ECX)和 S4..S6 在堆栈上传递。对于 S4S5(S3),输入 string 变量的当前值被插入堆栈后会被清除> 和 S6 只是指向变量的指针),并且在将值分配给 S1S2 之前。因此,S1S2 最终为零,S4S5 包含指向原始 'S 的指针' 删除之前的数据,S3S6 指向已删除的 string 变量。

调试器可以向您展示所有这些操作。如果在调用 MyProcedure() 的行处放置断点,然后打开 CPU View ,您将看到以下汇编指令:

StringTest.dpr.17: MyProcedure(S, S, S, S, S, 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, S, S, S, S, S, Res);
  WriteLn(Res);
end;

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

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, S, S, S, S));
end;

关于带字符串参数的 Delphi 程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35926637/

相关文章:

delphi - 如何使用Delphi在virtualtree组件中保存/加载文件?

delphi - 在delphi中分割串行数据

delphi - 创建并释放 TPopupMenu 使用的 TMenuItem

delphi - 如何为特定控件创建自己的自定义提示?

string - 询问用户并将响应发送回消息接收器

Delphi路径变量

delphi - 如何拦截(检测)粘贴命令到 TMemo 中?

delphi - TIdSMTP : How to fix the error SSL negotiation Failed

delphi - 框架继承和包中的重复文件

arrays - 你如何将 Delphi 中的文件读入字节数组?