1

我在使用 Ada 记录类型时遇到了一些问题。我正在使用 Sequential_IO 读取二进制文件。为此,我必须使用大小是文件大小倍数的类型。在我的情况下,我需要一个 50 字节的结构,所以我创建了一个这样的类型(“Vecteur”是一个 3 个浮点数的数组):

type Double_Byte is mod 2 ** 16; for Double_Byte'Size use 16;

type Triangle is
    record
        Normal : Vecteur(1..3);
        P1 : Vecteur(1..3);
        P2 : Vecteur(1..3);
        P3 : Vecteur(1..3);
        Byte_count1 : Double_Byte;
    end record;

当我使用三角形类型时,大小为 52 个字节,但当我在其中单独获取每个大小时,我发现 50 个字节。因为 52 不是我文件大小的倍数,所以我有执行错误。但我不知道如何修复这个大小,我进行了一些测试,我认为它来自 Double_Byte,因为当我从记录中删除它时,我发现它的大小为 48 字节,而当我放回它时,它又是 52 字节。

谢谢你的帮助。

4

2 回答 2

2

鉴于 Simon 的最新评论,使用 Sequential_IO可移植地执行此操作可能是不可能的;即,在某些机器(不支持未对齐访问)上读取文件可能会使其一半内容未对齐,因此在您访问它们时可能会失败。

我不禁感到更好的解决方案是将文件格式(通过与其他系统的兼容性固定)与机器格式(不是)分开。因此,转移到 Stream_IO 并在必要时编写您自己的ReadWrite原语(例如,将奇数大小的 Double_Byte 组件打包成 2 个字节,无论其在内存中的表示形式如何)将是一个更强大的解决方案。

然后,您可以保证与其他系统兼容的文件格式,以及保证工作的内部存储器格式。

于 2013-10-21T14:39:05.387 回答
1

Triangle除非您指定,否则编译器没有义务使用特定的大小。正如你不知道的那样,它会选择它认为适合快速访问数据的任何大小。即使您为记录的每个组件类型指定了表示细节,编译器仍可能选择为记录本身使用更多的空间而不是必要的。

考虑到您给出的大小,很明显 的一个组件Vecteur有 4 个字节,这为Triangle. 编译器现在选择添加 2 字节填充,以便记录大小是4 字节字大小的倍数。您可以使用以下方法覆盖此行为:

for Triangle'Size use 50 * 8;

这将强制编译器仅使用 50 个字节作为记录。由于这是一种紧密配合,因此只有一种表示记录的方式,无需进一步说明。如果您确实需要指定记录的精确表示方式,您可以使用记录表示子句

编辑:

表示子句指定类型的大小。但是,除非您另外指定,否则此类型的每个对象仍可能占用更多空间

pragma Pack (Triangle);

编辑2:

在西蒙发表评论后,我仔细研究了这一点,并意识到有一个更好、更清洁的解决方案。不要设置'Sizeand using pragma Pack,而是这样做:

for Triangle use record at mod 2;
   Normal      at 0  range 0 .. 95; 
   P1          at 12 range 0 .. 95;
   P2          at 24 range 0 .. 95;
   P3          at 36 range 0 .. 95;
   Byte_count1 at 48 range 0 .. 15;
end record;

初始mod 2定义记录要以 2 字节的倍数对齐。这消除了最后的填充而不需要pragma Pack(不能保证在每个编译器上都以相同的方式工作)。

于 2013-10-20T10:09:15.623 回答