Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access Types for Stack Allocated Array in Ada

Tags:

arrays

ada

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:

  1. Using the in out parameter passing mechanism.
  2. Reducing the storage requirements of my data type.

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.

like image 668
jsinglet Avatar asked Feb 24 '26 20:02

jsinglet


1 Answers

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.

like image 79
Simon Wright Avatar answered Feb 26 '26 11:02

Simon Wright