I'm trying to do something with array passing and access types. I've run into a situation where the stack size on an embedded system makes it difficult to pass around a large array through the typical parameter passing mechanism.
To save stack size, I've started using access types but I don't want to do dynamic allocation.
What I have is something like this:
type My_Array_Type is array (Natural range<>) of Integer;
type My_Array_Type_Ptr is access all My_Array_Type;
procedure Do_Stuff(Things : My_Array_Type_Ptr) is
begin
-- things
end Do_Stuff;
procedure Do_Stuff(Num_Things : Integer) is
Things : My_Array_Type_Ptr := new My_Array_Type(1..Num_Things);
begin
Do_Stuff(Things);
-- more things
end Do_Stuff;
HOWEVER, what I'd like to do is something like this:
type My_Array_Type is array (Natural range<>) of Integer;
procedure Do_Stuff(Things : access all My_Array_Type) is
begin
-- things
end Do_Stuff;
procedure Do_Stuff(Num_Things : Integer) is
Things : aliased My_Array_Type(1..Num_Things);
begin
Do_Stuff(Things'Access);
-- more things
end Do_Stuff;
But obviously it doesn't work.
Essentially, I want to pass a reference to the stack allocated array and change it in the other subprogram, but I don't want dynamically allocated memory. How can I do this?
Also, as a side note: I keep seeing conflicting information about if something is dynamically allocated if it has to be released or not -- I read most implementations don't have garbage collectors but don't need them. Can anyone clarify -- In the example I showed first, do I need to explicitly deallocate?
EDIT: After trying the solutions mentioned below, I settled on a combination of two things:
in out parameter passing mechanism. So rather than Integer I'm using:
type UInt8 is new Interfaces.Unsigned_8;
Which is:
type UInt8 is mod 2**8
with Size => 8;
This works perfectly, since my values aren't actually integers, they are in fact unsigned bytes.
In Ada, you really don’t need to use access types for this situation.
Remarks below for native Ada code; for imported (& I suppose exported) subprograms the generated code obviously needs to obey the foreign language conventions.
The mode of a parameter (whether you’re allowed to write to it, whether (if you’re allowed to write to it) it has some initial value) is distinct from the parameter passing mechanism.
If you have a parameter of size larger than a register and the parameter passing mechanism is not by-reference (i.e. by passing the address of the actual object), complain to your compiler vendor!
The Ada way would be like this:
with Ada.Text_IO; use Ada.Text_IO;
with System.Storage_Elements;
procedure Jsinglet is
type My_Array_Type is array (Natural range<>) of Integer;
procedure Do_Stuff_1 (Things : in out My_Array_Type) is
begin
Put_Line (System.Storage_Elements.To_Integer (Things'Address)'Img);
end Do_Stuff_1;
procedure Do_Stuff (Num_Things : Integer) is
Things : My_Array_Type (1 .. Num_Things);
begin
Put_Line (System.Storage_Elements.To_Integer (Things'Address)'Img);
Do_Stuff_1 (Things);
end Do_Stuff;
begin
Do_Stuff (42);
end Jsinglet;
Running the program results here in
$ ./jsinglet
140732831549024
140732831549024
showing that the address has been passed, not the value.
The in out mode on Do_Stuff_1’s parameter means that Do_Stuff_1 can read the contents of the array passed to it before writing to it.
out would mean that Do_Stuff_1 shouldn’t read the contents until it has itself written them (it can, but - depending on the parameter’s type - it may read uninitialized or default-initialized data)
in would mean that the contents couldn’t be written to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With