我在使用Delphi中的过程和字符串时遇到了问题。事实是,我希望看到输出字符串" 1S2S3S4S5S6S"但实际输出是" 1234S5S6"。在调试过程中,它表示没有初始化S1,S2,S3和S6字符串变量(S1,S2,S3,S6是'''''''' 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.
答案 0 :(得分:17)
您的S7
参数被声明为out
参数,因此编译器会在调用函数时将传递的变量设置为空字符串。您正在为所有参数传递相同的S
变量,包括输出参数,因此在函数内部使用参数值之前,S
的值将从内存中擦除。
进一步详细说明,该过程使用register
调用约定,其中S1
.. S3
在CPU寄存器(分别为EAX,EDX和ECX)中传递,{ {1}} .. S4
代替传递给堆栈。输入S6
变量在其当前值被推送到string
和S4
的堆栈后被清除,S5
和S3
只是指向变量),并在将值分配给S6
和S1
之前。因此,S2
和S1
结束为零,S2
和S4
包含指向擦除之前原始S5
数据的指针,'S'
和S3
指向已擦除的S6
变量。
调试器可以向您展示所有这些。如果在调用string
的行放置断点,然后打开CPU视图,您将看到以下汇编指令:
MyProcedure()
要解决此问题,您需要使用其他变量来接收输出:
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;
而不是使用String
参数返回新Result
的函数:
out