Ada 中堆栈分配数组的访问类型

Access Types for Stack Allocated Array in Ada

我正在尝试处理数组传递和访问类型。我已经 运行 遇到这样一种情况,嵌入式系统上的堆栈大小使得很难通过典型的参数传递机制传递大型数组。

为了节省堆栈大小,我已经开始使用访问类型,但我不想进行动态分配。

我的是这样的:

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;

但是,我想做的是这样的:

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;

但是显然不行。

本质上,我想传递对堆栈分配数组的引用并在另一个子程序中更改它,但我不想动态分配内存。我该怎么做?

此外,作为旁注:我一直看到关于某些东西是否必须被释放是否动态分配的相互矛盾的信息——我读到大多数实现没有垃圾收集器,但不需要它们。谁能澄清——在我首先展示的示例中,我是否需要显式解除分配?

编辑: 在尝试了下面提到的解决方案之后,我决定将两件事结合起来:

  1. 使用in out参数传递机制。
  2. 减少我的数据类型的存储要求。

所以我使用的不是 Integer

type UInt8 is new Interfaces.Unsigned_8;

即:

type UInt8 is mod 2**8
     with Size => 8;

这非常有效,因为我的值实际上不是整数,它们实际上是无符号字节。

在 Ada 中,您真的不需要为这种情况使用访问类型。

以下针对本机 Ada 代码的备注;对于导入的(我想是导出的)子程序,生成的代码显然需要遵守外语约定。

参数的模式(是否允许写入,是否(如果允许写入)它是否有一些初始值)与参数传递机制不同。

如果您的参数大小大于寄存器并且参数传递机制不是按引用(即传递实际对象的地址),请向您的编译器供应商投诉!

Ada 的方式是这样的:

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;

运行 程序结果在

$ ./jsinglet 
 140732831549024
 140732831549024

显示传递的是地址,不是值。

Do_Stuff_1参数的in out模式意味着Do_Stuff_1可以在写入之前读取传递给它的数组的内容。

out 意味着 Do_Stuff_1 在它自己写入内容之前不应读取内容(它 可以 ,但是 - 取决于参数的type - 它可能读取未初始化或默认初始化的数据)

in表示无法写入内容

从 Ada2012 开始,您可以将参数标记为 aliased,它们将通过引用传递,但您的源对象也必须被标记或别名。

编辑:它不能是数组,所以请看下面。不过,别名参数确实适用于整数、枚举、记录等类型。

您还可以将数组包装在标记或有限记录中,以强制编译器使用引用传递,因为它们是 "by reference" 类型

type My_Array_Type is array (Natural range<>) of Integer;
type By_Reference(Length : Natural) is tagged record  -- or limited
   Elements : My_Array_Type(1..Length);
end record;

procedure Do_Stuff(Things : in out By_Reference) is
begin
 -- things 
end Do_Stuff;

procedure Do_Stuff(Num_Things : Integer) is
  Things : By_Reference(Num_Things);
begin
  Do_Stuff(Things);
  -- more things
end Do_Stuff;

对于您的释放问题,您的示例必须显式释放内存。有一些方法可以获得自动释放:

  • 带垃圾收集功能的编译器(我知道none)
  • 提供它的自定义第 3 方库
  • 使用来自Ada.Containers
  • 的支架或容器
  • 使用具有指定存储大小的本地(非图书馆级别)命名访问类型(您的访问类型是图书馆级别并且没有指定存储大小)。当访问类型超出范围时,它将解除分配。