记录的Ada pragma Pack或Alignment属性?

记录的Ada pragma Pack或Alignment属性?,ada,memory-alignment,Ada,Memory Alignment,由于我第一次发现了对齐问题,我不确定哪种方法是处理这些问题的最佳/最安全的方法。我有一个记录,我正在序列化以通过流发送,反之亦然,因此它必须符合接口规范,并且不包含填充 给定示例记录: type MyRecord is record a : Unsigned_8; b : Unsigned_32; end record; 默认情况下,这需要8个字节,但我可以使用2种方法删除打包: for MyRecord'Alignment use 1; 或 我发现了一些与C示例相关的问题,但没有找到一个明

由于我第一次发现了对齐问题,我不确定哪种方法是处理这些问题的最佳/最安全的方法。我有一个记录,我正在序列化以通过流发送,反之亦然,因此它必须符合接口规范,并且不包含填充

给定示例记录:

type MyRecord is record
a : Unsigned_8;
b : Unsigned_32;
end record;
默认情况下,这需要8个字节,但我可以使用2种方法删除打包:

for MyRecord'Alignment use 1;

我发现了一些与C示例相关的问题,但没有找到一个明确的答案:哪种方法最合适,如何确定使用哪种方法,或者它们是否等效

更新


当我在我的“真实”代码上而不是在一个基本示例上尝试这两种方法时,我发现对齐属性达到了我想要的效果。pragma Pack显著减少了大小,但未确认,但我假设它已打包了我正在使用的许多枚举类型,覆盖了应用于每个类型的“size use 8”属性。

如果您想要完全控制,我想您需要记录表示子句:

for MyRecord'Size use 40;
for MyRecord use record 
    a at 0 range 0 .. 7;
    b at 1 range 0 .. 31;
end record;
(或者,我可能把这里的一些指数搞乱了)


注意:根据Simon的评论编辑,如果您想要完全控制,我想您需要记录表示条款:

for MyRecord'Size use 40;
for MyRecord use record 
    a at 0 range 0 .. 7;
    b at 1 range 0 .. 31;
end record;
(或者,我可能把这里的一些指数搞乱了)

注意:根据Simon的评论进行编辑,因为您可以不带任何陈述子句而离开
MyRecord
,并使用默认的
MyRecord'Write
MyRecord'Read
;说

对于基本类型,读取(和写入)类型T的流大小所暗示的流元素数量;这些流元素的表示由实现定义。对于复合类型,按规范顺序调用每个组件的Write或Read属性,即数组的最后一个维度变化最快(除非数组的约定是Fortran,在这种情况下,它是第一个维度变化最快)和记录的位置聚合顺序

GNAT实现(以及其他实现)的一个可能缺点是,
'Write
'Read
在对底层网络软件的调用中调用每一端。正常情况下,这不是一个问题(除了可能的低效),但如果您使用的是
TCP\u NODELAY
(或者更糟糕的是,UDP),则这不是您想要的行为

重载
'Write
会返回到原始问题(但至少它仅限于重载过程,因此程序的其余部分可以处理正确对齐的数据)

为此,我使用了内存流(特别是UDP情况)
'将
写入内存流,然后将
流元素数组
发送到套接字。一个例子是
ColdFrame.Memory\u Streams
(,)。

因为您可以不使用任何表示子句而离开
MyRecord
,并使用默认的
MyRecord'Write
MyRecord'Read
;说

对于基本类型,读取(和写入)类型T的流大小所暗示的流元素数量;这些流元素的表示由实现定义。对于复合类型,按规范顺序调用每个组件的Write或Read属性,即数组的最后一个维度变化最快(除非数组的约定是Fortran,在这种情况下,它是第一个维度变化最快)和记录的位置聚合顺序

GNAT实现(以及其他实现)的一个可能缺点是,
'Write
'Read
在对底层网络软件的调用中调用每一端。正常情况下,这不是一个问题(除了可能的低效),但如果您使用的是
TCP\u NODELAY
(或者更糟糕的是,UDP),则这不是您想要的行为

重载
'Write
会返回到原始问题(但至少它仅限于重载过程,因此程序的其余部分可以处理正确对齐的数据)


为此,我使用了内存流(特别是UDP情况)
'将
写入内存流,然后将
流元素数组
发送到套接字。一个例子是
ColdFrame.Memory\u在1范围0时流
(,)。

b。。31我想!representation子句是否与写入流相关?(现在懒得去查。)@jacobsparrenadersen:对于流,我会定义自己的读写来定义wire格式,这与编译器如何将记录打包到内存中无关。。31我想!representation子句是否与写入流相关?(现在懒得去查。)@jacobsparrenadersen:对于一个流,我会定义自己的读写来定义wire格式,与编译器如何在内存中打包记录无关。+1。应该使用打包来控制内存中的表示,而不是流表示。如果您需要“在线”特定格式(因为另一端需要该格式),您可以重载默认过程来生成该格式,而不考虑内存中的打包方式。当我这样做时,它会为每个数据包发送一个字段,而不是为每个数据包发送整个序列化记录?谢谢Simon。编辑看起来像是我问题的解决方案。我目前正在使用流元素数组,因为它可以轻松满足我的几个应用程序需求。我在尝试未经检查地转换为流元素数组时发现对齐问题。这还应该解决我的最后一个问题,即未经检查的转换将无符号的_32 LSB(字节)放在第一位,其中我的流规范是MSB优先。如果流规范完全是big-endian(也称为网络字节顺序),您可能希望查看修改Ada运行时以自动转换为网络字节顺序,如所示。我明白了