2013-10-20 22 views
1

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

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个字节。

谢谢你的帮助。

回答

1

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

考虑到您提供的尺寸,似乎很明显,Vecteur的一个组件有4个字节,因此Triangle的总有效负载为50个字节。编译器现在选择添加2个字节的填充,以便记录大小是4-byte word大小的倍数。您可以用下列方法覆盖此行为:

for Triangle'Size use 50 * 8; 

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

编辑:

的表示子句为类型的大小。然而,这种类型的每个对象仍可能占用更多的空间,除非你另外指定

pragma Pack (Triangle); 

编辑2:

西蒙的评论后,我曾在这个定睛一看,意识到有一个更好更清洁的解决方案。而不是设置'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(这不能保证在每个编译器上都以相同的方式工作)。

+0

谢谢你的回答。我只是试图把你说的大小,但我仍然有同样的问题,最后的大小是52字节... –

+0

啊,是的,我忘了一些东西,看我的编辑。 – flyx

+0

现在感谢您的支持。 –

2

鉴于Simon的最新评论,使用Sequential_IO可能无法做到这一点便携式;即在某些机器上读取文件(不支持未对齐的访问)可能会使其内容的一半保持不对齐,因此在访问它们时可能会失败。

我不禁觉得更好的解决办法是将数据格式(通过与其他系统的兼容性来解决)与数据格式(不是)分开。因此,如果需要(例如,将奇数大小的Double_Byte组件打包为2个字节,无论它在内存中的表示如何),都将转移到Stream_IO并编写您自己的基本代码ReadWrite,这将是一个更强大的解决方案。

然后你可以保证文件格式与其他系统兼容,并保证内存格式的工作。