Stream 从Ada中的流读取记录组件的数据时,如何调整/匹配记录组件的大小?

Stream 从Ada中的流读取记录组件的数据时,如何调整/匹配记录组件的大小?,stream,embedded,ada,Stream,Embedded,Ada,非常具体的问题,但我们这里有一些优秀的Ada人员,所以我想听听他们的想法。我正在从一个用于嵌入式系统的文件中读取数据。我处理的数据块总是有一个可预测的头格式…但是有一个问题…数据有效负载长度是在有效负载发生之前作为格式的一部分给出的。因此,在读取报头中已知位置的某个字节之前,我不知道有效负载的大小。这些块一个接一个地出现 字面上的格式是([]用于可读性): [2字节标签][1字节有效负载长度(LSB)][1字节有效负载长度(MSB)][有效负载] 有效负载是人类可读的配置文本。下一个标记将是前一

非常具体的问题,但我们这里有一些优秀的Ada人员,所以我想听听他们的想法。我正在从一个用于嵌入式系统的文件中读取数据。我处理的数据块总是有一个可预测的头格式…但是有一个问题…数据有效负载长度是在有效负载发生之前作为格式的一部分给出的。因此,在读取报头中已知位置的某个字节之前,我不知道有效负载的大小。这些块一个接一个地出现

字面上的格式是([]用于可读性):

[2字节标签][1字节有效负载长度(LSB)][1字节有效负载长度(MSB)][有效负载]

有效负载是人类可读的配置文本。下一个标记将是前一个有效负载之后的下两个字节,依此类推,直到我在最后一个有效负载之后没有看到任何匹配的已知标记。那我就知道我完了

我正在使用direct_IO流从文件中读取这些内容,但我可能会切换到更通用的流,然后开始执行转换

我想在一天结束时将所有这些存储在一个简单的记录中 我正在寻找一种技术,我可以读入数据并读取第三个字节,我现在知道有效负载的大小,并且可以调整数组或字符串组件的大小,以便在记录已经用作读取缓冲区的情况下保存数据。也就是说,我需要读取中的标记和长度数据,所以我希望立即将它们存储在记录中。如果可以的话,我想将有效载荷存储在同一个记录中。我可以考虑使用Access类型并动态创建有效载荷存储,但这意味着我必须在3字节之后停止读取,DO工作,然后继续。此外,这意味着由于对象的表示形式不再与expect区块格式匹配,因此写入也会遇到同样的问题

我正在考虑尝试使用一个记录来保存所有这些内容,并使用有效负载大小的判别式,在该记录上使用一个表示子句来模拟上述格式。由于鉴别器是记录和数据块中的第三个字节,我可能能够进行对话,并简单地将数据“放置”到对象中……但在实例化记录时,我无法在不读取标记和长度的情况下调整组件的大小。我假设我不能同时读取和创建对象,所以要创建对象,我需要一个长度。虽然我可以继续摆弄文件的位置,阅读我需要的内容,然后回到开头,然后创建并使用整个块,但我知道必须有更好的“Ada”方法

是否有一种方法可以使用representation子句将头填充到记录中,并且当使用数据中的值填充判别式时,将设置记录数组或字符串有效负载组件大小

此外,这不仅仅是为了阅读,我需要找到一种很好的方法,在配置更改时将这种精确格式输出到文件中。所以我希望使用一个表示子句来匹配底层的格式,这样我就可以将对象直接“写入”到文件中,它将是正确的格式。我希望在阅读方面也能这样做

到目前为止,我看到的所有Ada读取示例都是已知长度(或已知最大长度)的记录,其中记录读取静态大小的数据块

是否有人举了一个例子,或者可以为我指出如何使用这种方法来处理这种大小可变的负载的正确方向

谢谢你能提供的帮助


-Josh

基本上,这样做的方式是进行部分读取,足以获得字节数,然后将其余数据读取到一个有区别的记录中

类似于伪Ada中的以下内容:

type Payloads is array (Payload_Sizes range <>) of Your_One_Byte_Payload_Type;

type Data (Payload_Length : Payload_Sizes) is
   record
      Tag : Tag_Type;
      Payload : Payloads(1 .. Payload_Length);
   end record;

for Data use record
   Tag            at 0 range 0 .. 15;
   Payload_Length at 2 range 0 .. 15;
   -- Omit a rep spec for Payload
end record;
(您需要制定退出标准。)


然后,数据项将根据有效负载长度动态调整大小。但是,要注意,如果该长度是奇数,因为可能会出现填充…

这种情况正是属性
输入在语言中的作用

如果您还拥有首先将数据写入流的代码,那么这很容易。只用

Myobject : Discriminated_Record := Discriminated_Record'input (Some_Stream'access);
(当然,在编写时使用
”输出

如果您必须读入其他人的格式化数据,它会变得稍微复杂一点。您必须实现自己的
输入
例程

function Discriminated_Record_Input 
    (Stream : access Ada.Streams.Root_Stream_Type'class) 
return Discriminated_Record;
for Discriminated_Record'input use Discriminated_Record_Input;
在实现
判别式\u记录\u输入时
,您可以通过在声明部分执行所有操作或使用本地声明块来绕过判别式问题。 (警告:未编译代码)


这样做的主要缺点是数据可能会被复制两次(一次复制到本地常量,然后再从那里复制到
MyObject
)。一个好的优化器可能会解决这个问题,向语言添加左值引用也会解决这个问题(但我不知道这是否在考虑中)。

基于Marc Cs&TEDs答案,需要考虑以下几点:

  • 正如你提到的,这是一个嵌入式系统,我也会 阅读有关动态内存分配的项目要求, 许多嵌入式系统明确禁止动态内存 分配/解除分配。(检查ada.streams的实现)

  • 您描述的格式让人想起卫星有效载荷 我说得对吗?如果是这样,请仔细阅读规范 “尺寸”通常更准确地称为“最大可转位偏移” 从这一点开始,从0'开始,也称为大小-1

  • 一个有区别的记录可能是一条路,但你可能不得不这样做 使其成为具有长度字段(而不是长度字段)的不可变记录 区别)以保证您的程序不会分配太多 很多记忆。将其修正为您的“合理最大值”


  • 对不起,我中途停读了:-(很好,你没有
    function Discriminated_Record_Input 
        (Stream : access Ada.Streams.Root_Stream_Type'class) 
    return Discriminated_Record;
    for Discriminated_Record'input use Discriminated_Record_Input;
    
    function Discriminated_Record_Input
        (Stream : access Ada.Streams.Root_Stream_Type'class) 
    return Discriminated_Record is
    
        Size : constant Natural := Natural'input(Stream);
        Data : constant Discriminated_Record_Input 
            := (Size, (others => Byte_Type'input(Stream));
    begin
        return Data;
    end Discriminated_Record_Input;