Reputation: 2786
The following is illegal 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;
and the compiler produces the error:
object subtype must statically match designated subtype
on the last line. The workaround I have seen is to explicitly initialize the array like this:
bytes : aliased Byte_Array := (0 .. 9999 => 0);
However, this does not work for me as I have nonvolatile data stored at address 16#0040_0000#
that cannot be overwritten. What are my options?
More info:
I would like to add that you can avoid explicitly initializing the array via:
bytes : aliased Byte_Array := (0 .. 9999 => <>);
However, this still fails to compile, producing the different error:
aliased object "bytes" with unconstrained array nominal subtype
can overlay only aliased object with compatible subtype
on the line for bytes'Address use To_Address(16#0040_0000#);
.
Upvotes: 2
Views: 566
Reputation: 25491
Would it help to make your own sort of 'accessor'? something like
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;
with output
$ ./byte_arrays
10000
0000000000400000
[later] For FSF GNAT 10.1.0 on macOS, these changes work:
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
’s parameter has to be aliased so that it’s passed by reference rather than on the stack. Of course, you have to be careful not to delete it while the Standard_Access
is extant, so perhaps best always declared at package level.
Upvotes: 4