Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2010-04

"dynamic array of char" vs. "out array of char"

4 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Seth Grover

Observe the following test program (http://pastebin.org/186091 for those who prefer):

============================================================
program dynarrayout;
{$mode objfpc}{$H+}
uses
  SysUtils;
  procedure DoItVar(var yourArray : array of char);
  begin
  end;
  procedure DoItOut(out yourArray : array of char);
  begin
  end;
type
  DynCharArray = array of char;
var
  myArray : DynCharArray;
  myArray2 : DynCharArray;
begin
  SetLength(myArray, 64);
  try
    FillChar(myArray[0], Length(myArray), '!');
    DoItVar(myArray);
    writeln('DoItVar is ok');
  except
    on E : Exception do begin
      writeln('Exception calling DoItVar: ', E.Message);
    end;
  end;
  SetLength(myArray, 0);
  SetLength(myArray2, 64);
  try
    FillChar(myArray2[0], Length(myArray2), '~');
    DoItOut(myArray2);
    writeln('DoItOut is ok');
  except
    on E : Exception do begin
      writeln('Exception calling DoItOut: ', E.Message);
    end;
  end;
  SetLength(myArray2, 64);
end.
============================================================

So basically I have a type defined as a dynamic array of characters, which I fill with some data. If I have a function which takes a parameter which is a "var array of char" into which I pass a variable of my dynamic array type it works fine. However, if I have a function where the parameter is an "out array of char", I get a crash when I try to pass in my variable.

Is this behavior correct? Can someone explain this to me? I thought that the only difference between "var" and "out" was whether or not the compiler warned you about uninitialized data.

Thanks,

-SG

This email is fiction. Any resemblance to actual events or persons living or dead is purely coincidental. Seth Grover sethdgrover[at]gmail[dot]com

Reply by email

Graeme Geldenhuys
to Seth Grover
Seth Grover wrote
Is this behavior correct? Can someone explain this to me? I thought that the only difference between "var" and "out" was whether or not the compiler warned you about uninitialized data.

Changing those two procedures to the following code shown below works fine. I guess 'out' parameters are more strict with the types. Also, your initial code for the second array should actually be inside the DoItOut() procedure. All data contained in a variable passed to a procedure with a 'out' parameter is discarded.

---------------------------------
type
 DynCharArray = array of char;
 procedure DoItVar(var yourArray : DynCharArray);
 begin
 end;
 procedure DoItOut(out yourArray : DynCharArray);
 begin
 end;
----------------------------------
Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://opensoft.homeip.net/fpgui/

Reply by email

Jonas Maebe
to Seth Grover: Observe the following test program (http://pastebin.org/186091 for those who prefer):…
Seth Grover wrote 8 lines
So basically I have a type defined as a dynamic array of characters, which I fill with some data. If I have a function which takes a parameter which is a "var array of char" into which I pass a variable of my dynamic array type it works fine. However, if I have a function where the parameter is an "out array of char", I get a crash when I try to pass in my variable. Is this behavior correct?

No.

Can someone explain this to me?

The compiler should simply refuse to compile your program. Both procedure calls are wrong. You cannot (should not be able to) pass a dynamic array as a var/out parameter to an open array. The declarations of the procedures that Graeme posted are correct (in that case, the parameter types are dynamic arrays rather than open arrays).

And before we get another endless discussion: yes, it is confusing/unfortunate that the declarations for dynamic arrays and open arrays are identical and that "array of byte" means something completely different depending on whether it's used to define a variable or type (dynamic array) or a parameter (open array).

I thought that the only difference between "var" and "out" was whether or not the compiler warned you about uninitialized data.

It is not. In case of reference counted data, "out" parameters are finalised prior to calling the routine (reason: "out" was introduced by Delphi for COM interoperability, which mandates this behaviour). That may be part of the reason why the crash occurs, but I'm not sure. It doesn't matter however, since as mentioned above the compiler should refuse the code.

Jonas

Reply by email

Seth Grover
to Seth Grover: Observe the following test program (http://pastebin.org/186091 for those who prefer):…
Graeme wrote
Changing those two procedures to the following code shown below works fine. ... Also, your initial code for the second array should actually be inside the DoItOut() procedure

Yes, I know it works if you change the "array of char" parameters to simply reflect the dynamic array type. I was doing it that way to illustrate the crash. Also, I know the "fillchar" on the second example is ineffectual, however, it's how you get it to crash. If you don't have something in the array before the second call, it doesn't crash. This is because in the call to fpc_dynarray_decr_ref it appears to be dereferencing a pointer that's already dereferenced, but if the array is empty to begin with it just so happens that the data there is full of #0 characters so it doesn't make it past the "nil" check.

Jonas, thank you for the explanation about "out" vs. "var" when it comes to reference counted data. I'd not stopped to think about it, but that makes perfect sense. And, looking at the assembly code, you are correct, it is the attempt to get the reference count that causes it to crash.

The compiler should simply refuse to compile your program.

As for that, I understand what you're saying, but I'm not sure I feel the same way. Or, better said, I am glad that it *does* work (as long as I use "var" instead of "out.") The reason being is I have quite an extensive unit which does manipulations on arrays of characters: however, I have some variables in records which are declared as static, fixed arrays and others declared like "type myType = array of char." As it currently works, I am able to pass both kinds as open array of char arguments and it all just works (well, now that I've gone through and replaced the "out" with "var" :)). When I say it just works, I mean the the correct pointer and high bound is passed in both cases. If the compiler were to forbid me to do that I'd be unable to use a single set of these routines for both cases.

From what I could see in the assembler code, when the parameter was

declared as "out whatever : array of char" and I passed in a typed dynamic array variable, in the call to fpc_dynarray_decr_ref called before my procedure was called it appears it was trying to dereference the memory where the array data was stored, but that register already contains the pointer to the data, so there's no need to dereference it. However, once I realized that I really wanted "var" rather than "out", the call to fpc_dynarray_decr_ref is, of course, no longer being made, and it just works.

Thanks again for the input.

And, as a side note, as I tell all my developer friends, the FPC community of developers and users is just top-notch. Thanks so much for the effort and high quality that is the Free Pascal compiler, and for always being so informative, helpful, and accessible when it comes to the mailing list discussions. You guys really are a class act. At my company we're just finishing converting a couple of million lines of code from Modula-2 to Object Pascal using the Free Pascal compiler and it's incredible how smooth the transition has been. And when I have run into roadblocks or questions, the mailing lists have been so helpful. Anyway, I just wanted to say "thanks."

-Seth

This email is fiction. Any resemblance to actual events or persons living or dead is purely coincidental. Seth Grover sethdgrover[at]gmail[dot]com On Tue, Apr 27, 2010 at 3:21 PM, Seth Grover wrote: > Observe the following test program (http://pastebin.org/186091 for > those who prefer): > > ============================================================ > program dynarrayout; > > {$mode objfpc}{$H+} > > uses >  SysUtils; > >  procedure DoItVar(var yourArray : array of char); >  begin >  end; > >  procedure DoItOut(out yourArray : array of char); >  begin >  end; > > type >  DynCharArray = array of char; > > var >  myArray : DynCharArray; >  myArray2 : DynCharArray; > begin >  SetLength(myArray, 64); >  try >    FillChar(myArray[0], Length(myArray), '!'); >    DoItVar(myArray); >    writeln('DoItVar is ok'); >  except >    on E : Exception do begin >      writeln('Exception calling DoItVar: ', E.Message); >    end; >  end; >  SetLength(myArray, 0); > >  SetLength(myArray2, 64); >  try >    FillChar(myArray2[0], Length(myArray2), '~'); >    DoItOut(myArray2); >    writeln('DoItOut is ok'); >  except >    on E : Exception do begin >      writeln('Exception calling DoItOut: ', E.Message); >    end; >  end; >  SetLength(myArray2, 64); > end. > ============================================================ > > So basically I have a type defined as a dynamic array of characters, > which I fill with some data. If I have a function which takes a > parameter which is a "var array of char" into which I pass a variable > of my dynamic array type it works fine. However, if I have a function > where the parameter is an "out array of char", I get a crash when I > try to pass in my variable. > > Is this behavior correct? Can someone explain this to me? I thought > that the only difference between "var" and "out" was whether or not > the compiler warned you about uninitialized data. > > Thanks, > > -SG > > -- > This email is fiction. Any resemblance to actual events > or persons living or dead is purely coincidental. > > Seth Grover > sethdgrover[at]gmail[dot]com >

Reply by email