首页 文章

Ada:记录类型的变体大小

提问于
浏览
1

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

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字节 .

谢谢你的帮助 .

2 回答

  • 2

    除非您指定,否则编译器绝不必使用 Triangle 的特定大小 . 如果不这样做,它会选择它认为适合的任何大小来快速访问数据 . 即使您为记录的每个组件类型指定了表示详细信息,编译器仍可能选择为记录本身使用比必要更多的空间 .

    考虑到你给出的大小, Vecteur 的一个组件显然有4个字节,这为 Triangle 提供了50个字节的总有效负载 . 编译器现在选择添加2个字节的填充,以便记录大小是4-byte word的大小的倍数 . 您可以使用以下方式覆盖此行为

    for Triangle'Size use 50 * 8;
    

    这将强制编译器仅使用50个字节作为记录 . 由于这是一个紧密配合,只有一种方式来表示记录,不需要进一步的说明 . 如果确实需要指定记录的准确程度,可以使用record representation clause .

    Edit:

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

    pragma Pack (Triangle);
    

    Edit 2:

    在Simon的评论之后,我仔细研究了这一点,并意识到有一个更好,更清洁的解决方案 . 而不是设置 'Size 并使用 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 (不保证在每个编译器上以相同的方式工作) .

  • 1

    鉴于Simon的最新评论,可能无法使用Sequential_IO进行移植;也就是说,在某些机器上读取文件(不支持未对齐访问)可能会使其内容的一半未对齐,因此在访问它们时可能会失败 .

    我不禁感到更好的解决方案是将文件格式(通过与其他系统的兼容性修复)从机器格式(不是)中分离出来 . 因此,移动到Stream_IO并在必要时编写自己的 ReadWrite 基元(例如,将奇数大小的Double_Byte组件打包成2个字节,无论其在内存中的表示如何)将是更强大的解决方案 .

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

相关问题