Ada访问静态地址的不受限制的类型

问题描述

以下是非法的Ada:

type Byte_Array is array (Natural range <>) of Interfaces.Unsigned_8;
type Byte_Array_Access is access all Byte_Array;
bytes : aliased Byte_Array(0 .. 9999);
for bytes'Address use To_Address(16#0040_0000#);
bytes_Access : Byte_Array_Access := bytes'Access;

编译器产生错误

object subtype must statically match designated subtype

在最后一行。我所见的解决方法是像这样显式初始化数组:

bytes : aliased Byte_Array := (0 .. 9999 => 0);

但是,这对我不起作用,因为我的非易失性数据存储在地址16#0040_0000#中,并且无法覆盖。我有什么选择?


更多信息:

我想补充一点,您可以避免通过以下方式显式初始化数组:

bytes : aliased Byte_Array := (0 .. 9999 => <>);

但是,它仍然无法编译,产生了不同的错误

aliased object "bytes" with unconstrained array nominal subtype
can overlay only aliased object with compatible subtype

for bytes'Address use To_Address(16#0040_0000#);行上。

解决方法

创建自己的“访问者”对您有帮助吗?像

with Ada.Text_IO; use Ada.Text_IO;
with Interfaces;
with System;
with System.Address_Image;
procedure Byte_Arrays is
   type Byte_Array is array (Natural range <>) of Interfaces.Unsigned_8;
   package Access_Byte_Array is
      type Byte_Array_Access is private;
      function Form_Access (Of_Array : Byte_Array) return Byte_Array_Access;
      function Address (Of_Array : Byte_Array_Access) return System.Address;
      function Length (Of_Array : Byte_Array_Access) return Integer;
   private
      type Byte_Array_Access is record
         The_Array : System.Address;
         First : Natural;
         Last : Integer;  -- could have zero length
      end record;
      function Address (Of_Array : Byte_Array_Access) return System.Address
      is (Of_Array.The_Array);
      function Length (Of_Array : Byte_Array_Access) return Integer is
        (if Of_Array.Last < Of_Array.First
         then 0
         else Of_Array.Last - Of_Array.First + 1);
   end Access_Byte_Array;
   package body Access_Byte_Array is
      function Form_Access (Of_Array : Byte_Array) return Byte_Array_Access
      is
      begin
         return (The_Array => Of_Array'Address,First => Of_Array'First,Last => Of_Array'Last);
      end Form_Access;
   end Access_Byte_Array;
   use Access_Byte_Array;
   Bytes : aliased Byte_Array(0 .. -9999);
   for Bytes'Address use System'To_Address(16#0040_0000#);
   Bytes_Access : constant Byte_Array_Access := Form_Access (Bytes);
begin
   Put_Line (Length (Bytes_Access)'Image);
   Put_Line (System.Address_Image (Address (Bytes_Access)));
end Byte_Arrays;

有输出

$ ./byte_arrays 
 10000
0000000000400000

[稍后]对于macOS上的FSF GNAT 10.1.0,这些更改有效:

   type Standard_Access is access all Byte_Array;
...
      function Standard_Accessor
        (Of_Array : aliased Byte_Array_Access) return Standard_Access;
...

      type Bounds is record
         Lower : Integer;
         Upper : Integer;
      end record with Pack;
      type Byte_Array_Access is record
         The_Array  : System.Address;
         The_Bounds : Bounds;
      end record;
...
      function Standard_Accessor
        (Of_Array : aliased Byte_Array_Access) return Standard_Access
      is
         type Raw_Accessor is record
            Contents : System.Address;
            Bounds_P : System.Address;
         end record with Pack;
         function Convert
         is new Ada.Unchecked_Conversion (Raw_Accessor,Standard_Access);
         Raw_Result : constant Raw_Accessor
           := (Contents => Of_Array.The_Array,Bounds_P => Of_Array.The_Bounds'Address);
      begin
         return Convert (Raw_Result);
      end Standard_Accessor;

Standard_Accessor的参数必须使用别名,以便通过引用而不是堆栈传递。当然,您必须注意不要在Standard_Access存在时将其删除,因此最好始终在程序包级别进行声明。