Io Ada:记录类型中的变量大小

Io Ada:记录类型中的变量大小,io,binary,size,record,ada,Io,Binary,Size,Record,Ada,我和Ada的打字记录有点问题。 我用顺序IO读取二进制文件。为此,我必须使用一种类型,其中大小是文件大小的倍数。在我的例子中,我需要一个50字节的结构,所以我创建了这样一个类型(“Vecteur”是一个3个浮点的数组): 当我使用类型三角形时,大小是52个字节,但当我单独计算其中每个三角形的大小时,我发现有50个字节。因为52不是文件大小的倍数,所以我有执行错误。但我不知道如何修复这个大小,我做了一些测试,我认为它来自双字节,因为当我从记录中删除它时,我发现它的大小是48字节,当我把它放回去时,

我和Ada的打字记录有点问题。 我用顺序IO读取二进制文件。为此,我必须使用一种类型,其中大小是文件大小的倍数。在我的例子中,我需要一个50字节的结构,所以我创建了这样一个类型(“Vecteur”是一个3个浮点的数组):

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


感谢您的帮助。

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

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

for Triangle'Size use 50 * 8;
这将迫使编译器对记录仅使用50字节。由于这是一种紧密配合,因此只有一种方法来表示记录,不需要进一步的规范。如果确实需要指定记录的精确表示方式,可以使用

编辑:

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

pragma Pack (Triangle);
编辑2:

在Simon的评论之后,我仔细研究了这一点,并意识到有一个更好、更干净的解决方案。不要设置
“大小”
并使用
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
(这并不保证在每个编译器上都能以相同的方式工作)。

鉴于Simon的最新评论,可能无法使用顺序IO以可移植的方式实现这一点;也就是说,在某些机器(不支持未对齐的访问)上读取文件可能会使其一半内容未对齐,因此在访问它们时可能会失败

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


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

谢谢您的回答。我只是试着把大小像你说的,但我仍然有同样的问题,最终的大小是52字节…这可能是一个蚊虫特定的修复;
-gnatR
开关显示GNAT仍然将
'Alignment
视为4,将
'Object\u Size
视为416,因此
三角形数组的组件保持正确的对齐,并且(具体地说)该类型的对象占用更多的空间。您可能是对的,谢谢。我在答案中添加了一个更简洁的解决方案。现在我们应该使用
”对齐
,而不是mod
处的
。但是这个解决方案意味着有一半的时间
浮动
组件会错位!这在x64_64硬件上似乎还可以,但效率可能很低,但在其他体系结构上可能不起作用。没有
Float
组件,
Double_Byte
是一种模块化类型。编辑:等等,没关系,矢量是浮动的,你说得对。
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;