Generics 是否可以将变量记录存储到Ada中的泛型类型?

Generics 是否可以将变量记录存储到Ada中的泛型类型?,generics,record,ada,Generics,Record,Ada,我有一个从套接字读取数据的通用库。请参阅问题末尾的代码清单 当My_Type是固定大小的类型时,这可以正常工作,但尝试使用此代码读取变量记录会引发存储错误,消息为对象太大 我知道通过套接字发送变体记录是可能的,因为我已经有了一个工作示例。我假设问题在于我将记录存储为泛型类型。无论变量记录是否具有默认判别式,都会引发异常。在这种情况下,是否有一种存储变体记录的方法 读者包装广告 with Sockets; use Sockets; with Sockets.Stream_IO; use Socke

我有一个从套接字读取数据的通用库。请参阅问题末尾的代码清单

My_Type
是固定大小的类型时,这可以正常工作,但尝试使用此代码读取变量记录会引发
存储错误,消息为
对象太大

我知道通过套接字发送变体记录是可能的,因为我已经有了一个工作示例。我假设问题在于我将记录存储为泛型类型。无论变量记录是否具有默认判别式,都会引发异常。在这种情况下,是否有一种存储变体记录的方法

读者包装广告

with Sockets; use Sockets;
with Sockets.Stream_IO; use Sockets.Stream_IO;

generic
  My_Type: private
package Reader_Pkg is
  task type Receive_Task_Type is
    entry Start(FD: Socket_FD);
  end Receive_Task_Type;
end Reader_Pkg;
reader_pkg.adb

package body Reader_Pkg is
  task body Receive_Task is
    Recv_Socket: Socket_FD;
    Recv_Stream: aliased Socket_Stream_Type;
  begin
    select
      accept Start (FD : Socket_FD) do
        Recv_Socket := FD;
        Initialize (Recv_Stream, Recv_Socket);
        declare
          Message: My_Type := My_Type'Input(Recv_Stream'Access); -- STORAGE_ERROR raised here
        begin
          -- Message gets processed here
        end;
      end Start;
    or
      terminate;
    end select;
  end Receive_Task;
end Reader_Pkg;

当然是。实际上,保存是容易的部分,加载则有点棘手,因为判别式是类型的一部分;也就是说,不可能有无约束变量存在。这与
s:String的问题相同编译器不能使用这样的变量,因为它不知道要为它分配多少内存

解决这个问题的一种方法是使用访问类型,因为我们可以访问不受约束的类型。下面就是这样一个解决方案

Pragma Ada_2012;
Pragma Assertion_Policy( Check );

With
System,
Text_Count,
Unchecked_Deallocation,     
Ada.Strings.Fixed,
Ada.Text_IO.Text_Streams;

Procedure Test is

Type Boolean_Array is array (Positive range <>) of Boolean
  with Pack, Component_Size => 1;    

Type Varient_Record( Length : Positive:= 3 ) is record
    Data : Boolean_Array(1..Length):= (others => True);
end record;

Test : constant Varient_Record:=
          (Data => (True, False, False), others => <>);

Function Associate( Name : String;
            Mode : Ada.Text_IO.File_Mode ) 
    Return Ada.Text_IO.File_Type is
Use Ada.Text_IO;
begin
Return Result : File_Type do
    Open(
      File  => Result,
      Name  => Name,
      Mode  => Mode
    );
end return;
End Associate;


Begin
    Ada.Text_IO.Put_Line("Starting Test:");

    SAVE:
    declare
        Test_File : Ada.Text_IO.File_Type:= 
          Associate( "testing.txt", Ada.Text_IO.Out_File);
        Test_Stream : Ada.Text_IO.Text_Streams.Stream_Access:=
          Ada.Text_IO.Text_Streams.Stream( Test_File );
    begin
        Varient_Record'Write( Test_Stream, Test );
            -- Needs an end-line or something to avoid END_ERROR on read.
        String'Write( Test_Stream, ASCII.CR & ASCII.LF );
        Ada.Text_IO.Close( Test_File );
    end SAVE;

    LOAD:
    declare
        Type Access_Varient is Access Varient_Record;
        Procedure Free is new Unchecked_Deallocation(
            Object => Varient_Record,
            Name   => Access_Varient
            );
        Loaded : Access_Varient:= New Varient_Record'(others=><>);
        Test_File : Ada.Text_IO.File_Type:= 
              Associate( "testing.txt", Ada.Text_IO.In_File);
        Test_Stream : Ada.Text_IO.Text_Streams.Stream_Access:=
          Ada.Text_IO.Text_Streams.Stream( Test_File );
    begin
        Varient_Record'Read( Test_Stream, Loaded.All );

        Ada.Text_IO.Put_Line( "Test and Loading are" &
              (if Test /= Loaded.All then " NOT " else " ") & 
            "the same." );

        Free(Loaded);

    Ada.Text_IO.Close( Test_File );
    End LOAD;


    Ada.Text_IO.Put_Line("Testing complete.");
End Test;
Pragma Ada_2012;
Pragma断言_策略(检查);
具有
系统,,
文本计数,
取消分配,
Ada.Strings.Fixed,
Ada.Text_IO.Text_流;
程序测试是
类型布尔\数组是布尔值的数组(正范围)
对于包装,组件_尺寸=>1;
类型变量_记录(长度:正:=3)为记录
数据:布尔_数组(1..Length):=(其他=>True);
结束记录;
测试:恒定变量记录:=
(数据=>(真、假、假),其他=>);
函数关联(名称:字符串;
模式:Ada.Text\u IO.File\u模式)
返回Ada.Text\u IO.File\u类型为
使用Ada.Text\u IO;
开始
返回结果:文件类型do
打开(
File=>Result,
Name=>Name,
模式=>模式
);
末端返回;
终端助理;
开始
Ada.Text_IO.Put_行(“开始测试:”);
保存:
声明
测试文件:Ada.Text\u IO.File\u类型:=
关联(“testing.txt”、Ada.Text\u IO.Out\u文件);
测试流:Ada.Text\u IO.Text\u Streams.Stream\u访问:=
Ada.Text\u IO.Text\u Streams.Stream(测试文件);
开始
变量记录的写入(测试流、测试);
--需要一个结束行或其他东西来避免读取时的结束错误。
字符串写入(测试流,ASCII.CR和ASCII.LF);
Ada.Text\u IO.Close(测试文件);
结束保存;
负载:
声明
类型访问变量为访问变量记录;
无过程是新的未经检查的释放(
对象=>Varient_记录,
名称=>Access\u变量
);
已加载:访问变量:=新变量记录“(其他=>);
测试文件:Ada.Text\u IO.File\u类型:=
关联(“testing.txt”,Ada.Text\u IO.In\u文件);
测试流:Ada.Text\u IO.Text\u Streams.Stream\u访问:=
Ada.Text\u IO.Text\u Streams.Stream(测试文件);
开始
变量记录读取(测试流,已加载。全部);
Ada.Text\u IO.Put\u行(“测试和加载为”&
(如果测试/=加载。全部,则为“非”或“其他”)&
“一样。”);
免费(已加载);
Ada.Text\u IO.Close(测试文件);
端部载荷;
Ada.Text_IO.Put_行(“测试完成”);
结束试验;

您不能以这种方式使用代码。在这里,消息在begin之后声明,这是非法的

但是,您可以使用以下内容:

declare
  Recv_Socket : Socket_FD;
  Recv_Stream : aliased Socket_Stream_Type;
begin
  -- maybe init your stream here
  declare
    Message : My_Type := My_Type'Input(Recv_Stream'Access);
  begin
    DoSomethingWithMessage(Message);
  end;
end;

如果
My\u Type
具有可变宽度,则在声明它时必须知道所使用实例的大小,并且给出初始值是指定变量大小的一种方法。

我知道您说过,无论该类型是否具有默认的鉴别器,都会出现问题,但我认为这可能与:

如果已判别类型的判别式具有默认的_表达式, 然后允许该类型的无约束变量,并且 可以通过分配给这样一个值来改变判别式的类型 变量如果没有为鉴别器提供默认值,则所有 该类型的变量通过显式约束或 或者根据它们的初始值;这种类型的判别式的值 初始化后无法更改变量

如果您声明一个类型,如

type Rec (Len : Natural) is record
   Data : String (1 .. Len);
end record;
然后,一个实例一旦创建,就会有一个固定值
Len
。然而,如果你说

type Rec (Len : Natural := 4) is record
   Data : String (1 .. Len);
end record;
然后可以更改实例中
Len
的值(仅通过分配给整个对象),这意味着(对于GNAT,其他一些编译器的做法不同),编译器必须在堆栈上保留足够的空间,以获得可能的最大值;在这种情况下,这意味着为长度为2^31-1的字符串保留足够的空间。这是行不通的

如果您在编译时启用了其他警告(我使用
-gnatwa
,这是所有常见的警告),GNAT将在编译时警告您这个问题。应使用
-fstack check
改进运行时检测

在上述情况下,GNAT说

sm.adb:20:09: warning: creation of "Rec" object may raise Storage_Error
避免此问题的一种方法可能是告诉编译器您将不会分配给对象:

Message: constant My_Type := My_Type'Input(Recv_Stream'Access);
         ^^^^^^^^
另一个(不期望编译器足够聪明来识别这种情况)是限制最大可能的大小:

subtype Length is Natural range 0 .. 1024;
type Rec (Len : Length := 4) is record
   Data : String (1 .. Len);
end record;

你的代码不可能是那样的,因为它不可能编译!我不认为存在默认的判别式会有什么不同,因为
输入首先读取判别式,然后准备一个数据区来接收指示的数据,然后读取数据。您是否正在使用
输出写入数据?(
'Write
不输出判别式;读写器必须匹配。)您使用的编译器/操作系统是什么?需要有关“我的类型”的更多信息。你试了什么没用的?@Si