Delphi 带有字符串参数的程序
Delphi procedures with string parameters
我在 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
而是在堆栈上传递。在 S4
和 S5
的当前值被压入堆栈后,输入 string
变量被清除(S3
和 S6
只是指向变量),并且在将值分配给 S1
和 S2
之前。因此,S1
和 S2
最终为零,S4
和 S5
包含指向擦除前原始 'S'
数据的指针,而 S3
和S6
指向已擦除的 string
变量。
调试器可以实际向您展示所有这些。如果你在调用MyProcedure()
的那一行打断点,然后打开CPU视图,你会看到下面的汇编指令:
StringTest.dpr.17: MyProcedure(S, S, S, S, S, S, S);
00405A6C 8B45FC mov eax,[ebp-] // [ebp-] is the current value of S
00405A6F 50 push eax // <-- assign S4
00405A70 8B45FC mov eax,[ebp-]
00405A73 50 push eax // <-- assign S5
00405A74 8D45FC lea eax,[ebp-]
00405A77 50 push eax // <-- assign S6
00405A78 8D45FC lea eax,[ebp-]
00405A7B E8B0EDFFFF call @UStrClr // <-- 'out' wipes out S!
00405A80 50 push eax // <-- assign S7
00405A81 8D4DFC lea ecx,[ebp-] // <-- assign S3
00405A84 8B55FC mov edx,[ebp-] // <-- assign S2
00405A87 8B45FC mov eax,[ebp-] // <-- 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
而不是使用 out
参数 returns 一个新的 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, S, S, S, S));
end;
我在 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
而是在堆栈上传递。在 S4
和 S5
的当前值被压入堆栈后,输入 string
变量被清除(S3
和 S6
只是指向变量),并且在将值分配给 S1
和 S2
之前。因此,S1
和 S2
最终为零,S4
和 S5
包含指向擦除前原始 'S'
数据的指针,而 S3
和S6
指向已擦除的 string
变量。
调试器可以实际向您展示所有这些。如果你在调用MyProcedure()
的那一行打断点,然后打开CPU视图,你会看到下面的汇编指令:
StringTest.dpr.17: MyProcedure(S, S, S, S, S, S, S);
00405A6C 8B45FC mov eax,[ebp-] // [ebp-] is the current value of S
00405A6F 50 push eax // <-- assign S4
00405A70 8B45FC mov eax,[ebp-]
00405A73 50 push eax // <-- assign S5
00405A74 8D45FC lea eax,[ebp-]
00405A77 50 push eax // <-- assign S6
00405A78 8D45FC lea eax,[ebp-]
00405A7B E8B0EDFFFF call @UStrClr // <-- 'out' wipes out S!
00405A80 50 push eax // <-- assign S7
00405A81 8D4DFC lea ecx,[ebp-] // <-- assign S3
00405A84 8B55FC mov edx,[ebp-] // <-- assign S2
00405A87 8B45FC mov eax,[ebp-] // <-- 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
而不是使用 out
参数 returns 一个新的 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, S, S, S, S));
end;