Twój parametr S7
została zadeklarowana jako parametr out
, więc kompilator będzie ustawić zmienną przekazany do pustej struny, gdy funkcja jest wywoływana. Przekazujesz tę samą zmienną S
dla wszystkich parametrów, łącznie z parametrem wyjściowym, dzięki czemu wartość S
zostanie wymazana z pamięci, zanim wartości parametrów zostaną użyte w funkcji.
celu dalszego dopracowania procedurę stosuje konwencję register
wywołującego, gdzie S1
.. S3
są przekazywane do rejestrów CPU (EAX EDX i ECX, odpowiednio) i S4
.. S6
są przekazywane na stosie, a nie. Zmienna wejściowa string
jest kasowana wyczyszczona po tym, jak jej bieżąca wartość jest pchana na stos dla S4
i S5
(S3
i S6
są tylko wskaźnikami do zmiennej), a przed wartością jest przypisana do S1
i S2
. Więc S1
i S2
skończyć zerowa, S4
i S5
zawierać odnośniki do oryginalnych danych 'S'
przed wytrzeć i S3
i S6
są wskazując na string
zmiennej, która została zniszczona.
Debugger może pokazać ci to wszystko w akcji. Jeśli umieścisz punkt przerwania na linii gdzie MyProcedure()
nazywa, a następnie otworzyć widok procesora, można zobaczyć następujące instrukcje montażu:
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
Aby rozwiązać ten problem, należy użyć innej zmiennej, aby otrzymać wyjście :
procedure Work;
var
S, Res: String;
begin
S := 'S';
Proc(S, S, S, S, S, S, Res);
WriteLn(Res);
end;
Alternatywnie, zmiany procedury do funkcji, która zwraca nowy String
poprzez jego Result
zamiast stosowania parametru 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;
Uwaga: Kiedy deklarujesz parametr z 'const', mówisz kompilatorowi, że nie powinien oczekiwać, że parametr zmieni się na czas trwania tej funkcji. Twoim obowiązkiem jest upewnić się, że dotrzymasz tej obietnicy; kompilator nie może tego dla ciebie sprawdzić. W tym przypadku modyfikujesz 'S' do' S7', jednocześnie twierdząc, że 'S2' i' S5' nie ulegną zmianie. –