Ada 访问静态地址的无约束类型

Ada Access to Unconstrained Type at Static Address

以下是非法的 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#); .

制作自己的 'accessor' 有帮助吗?像

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 存在时删除它,所以也许最好总是在包级别声明。