Pascal Viandier wrote:
I just hit something I do not really understand in the way GPC passes parameters to procedures. The following sample program:
Program ParamTest; Var S40 : String(40); I : Integer;
Procedure TstParams(S : String; IL : Integer); Begin WriteLn('Before: S=', S, ' IL=', IL); S := S + 'BBB'; { Using Concat() does the same } IL := IL + 4; WriteLn('After: S=', S, ' IL=', IL); End;
Begin S40 := 'AAA'; I := 4; TstParams(S40, I); End.
Produces the following output: Before: S=AAA IL=4 After: S=AAA IL=8
How come the string cannot be modified inside of the procedure (without impacting the global string) but the integer can? Until now, my understanding of the parameters passing mechanism was that when you pass a parameter by value, the procedure uses a local copy of it, and this copy may be modified locally. This mechanism seems to work for integers but not for strings! However, if the string modification is somewhat "illegal" at least GPC could issue a compilation warning.
The string can be modified, but not appended to. Value parameters of type `String' (without a given capacity) assume as capacity the length of the actual parameter, in this case 3.
To avoid it, you can declare the parameter of a given capacity, say `String (40)' (via a type-declaration, of course). Then, of course, you have to specify in advance how big the parameter can become. (But otherwise the compiler would have to guess that, that's why it doesn't work like this.)
I would be interested to understand better how this works, because this behavior causes bugs in the programs I am porting from SUN Pascal and perhaps in ways I don't see as clearly as in this example.
I don't know what Sun Pascal does. In Borland Pascal, all strings are limited to 255 chars, so you'd get that effect with `String (255)'.
To avoid artificial limits, it's often useful to declare local variables with a capacity based on the actual parameter, e.g. in your case:
Procedure TstParams(S : String; IL : Integer); Var Tmp: String (Length (S) + 3); Begin Tmp := S; WriteLn('Before: S=', Tmp, ' IL=', IL); Tmp := Tmp + 'BBB'; { Using Concat() does the same } IL := IL + 4; WriteLn('After: S=', Tmp, ' IL=', IL); End;
Or perhaps (depending on what you need):
Var Tmp: String (2 * Length (S));
Frank