简体   繁体   English

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

[英]Access Types for Stack Allocated Array in 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.使用输入in out参数传递机制。
  2. Reducing the storage requirements of my data type.减少我的数据类型的存储要求。

So rather than Integer I'm using:所以我使用的不是Integer

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.在 Ada 中,您真的不需要在这种情况下使用访问类型。

Remarks below for native Ada code;下面是原生 Ada 代码的备注; 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 (ie by passing the address of the actual object), complain to your compiler vendor!如果您有一个大小大于寄存器的参数并且参数传递机制不是通过引用(即通过传递实际对象的地址),请向您的编译器供应商投诉!

The Ada way would be like this: 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;

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. Do_Stuff_1参数的in out模式意味着Do_Stuff_1可以在写入之前读取传递给它的数组的内容。

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) out意味着Do_Stuff_1在它自己写入内容之前不应该读取内容(它可以,但是 - 取决于参数的类型 - 它可能读取未初始化或默认初始化的数据)

in would mean that the contents couldn't be written to. in意味着无法写入内容。

As of Ada2012 you can mark parameters as aliased and they will be passed by reference, but your source object must also be either tagged or aliased.从 Ada2012 开始,您可以将参数标记为别名,它们将通过引用传递,但您的源对象也必须被标记或别名。

EDIT: It cannot be an array either it appears, so look below.编辑:它既不能是数组,也不能是数组,所以请看下面。 Aliased parameters do work for types like integers, enumerations, records, etc. though.不过,别名参数确实适用于整数、枚举、记录等类型。

You can also wrap the array in a tagged or limited record to force the compiler to use by reference passing as those are "by reference" types您还可以将数组包装在标记或受限记录中,以强制编译器使用通过引用传递,因为它们是“通过引用”类型

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;

For your deallocation question, your example must explicitly deallocate the memory.对于您的解除分配问题,您的示例必须明确解除分配内存。 There are ways to get automatic deallocation:有几种方法可以自动解除分配:

  • Compiler with Garbage Collection (I know of none)带有垃圾收集的编译器(我不知道)
  • Custom 3rd party library that provides it提供它的自定义 3rd 方库
  • Use a holder or container from Ada.Containers使用 Ada.Containers 中的支架或容器
  • Use a local (non library level) named access type with a specified storage size (your access type is library level and has not storage size specified).使用具有指定存储大小的本地(非库级别)命名访问类型(您的访问类型是库级别且未指定存储大小)。 When the access type goes out of scope it will deallocate.当访问类型超出范围时,它将解除分配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM