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