あなたS7
パラメータはout
パラメータとして宣言されているので、関数が呼び出されたときに、コンパイラは、空白の文字列に渡された変数を設定します。同じS
変数を出力パラメーターを含むすべてのパラメーターに渡すので、パラメーター値が関数内で使用される前に、S
の値がメモリーから消去されます。手順はS1
.. S3
は、CPUレジスタ(それぞれ、EAX、EDX、およびECX)及びS4
に渡されregister
呼び出し規約を使用して、さらに詳しく説明する
.. S6
代わりにスタックに渡されます。変数string
は、現在値がS4
とS5
(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-$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
これを修正するには、出力を受け取るように別の変数を使用する必要があります:
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;
:
procedure Work;
var
S, Res: String;
begin
S := 'S';
Proc(S, S, S, S, S, S, Res);
WriteLn(Res);
end;
あるいは、その代わりResult
out
パラメータの使用を介して新しいString
を返す関数に手順を変更します
注意: 'const'でパラメータを宣言すると、コンパイラはその関数の実行中にパラメータが変更されることを期待しないように指示します。その約束を守るのはあなたの責任です。コンパイラはあなたのためにそれをチェックすることはできません。この場合、 'S7'を介して' S'を変更していると同時に、 'S2'と' S5'は変更しないと主張しています。 –