记录布局的静态比较



我有两条记录,其中一些字段需要在每条记录中的相同位置。尽管代码中对此进行了大量注释,但在10年后,程序员可能会在不更改另一条记录的情况下更改其中一条记录,我想创建一个静态检查,以确保没有发生这种情况。

我可以创建一个";活动的";按如下方式检查程序或功能:


procedure Main is
type SimpleRecord1 is record
FirstItem  : Integer;
SecondItem : Boolean;
ThirdItem  : Integer;
DoNotCare  : Float;
end record;
type SimpleRecord2 is record
Foo        : Integer;
Bar        : Boolean;
Baz        : Integer;
Rfc3092    : Boolean;
end record;
MyRecord1 : SimpleRecord1;
MyRecord2 : SimpleRecord2;
begin
Pragma Assert ((MyRecord1.FirstItem'Position = MyRecord2.Foo'Position) and
(MyRecord1.SecondItem'Position = MyRecord2.Bar'Position) and
(MyRecord1.ThirdItem'Position = MyRecord2.Baz'Position));
Put_Line ("The assert didn't fire");

end Main;

我担心前三个变量在两个记录中具有相同的偏移量。在实际代码中,每个记录中都有几十个其他变量,这些变量在记录之间并不相同。

然而,我真的希望这是一次检查,不是对记录的实例(MyRecord1,MyRecord2(,而是对记录本身(SimpleRecord1,SimpleRecord2(。然后可以将其放置在定义记录的.ads文件中。

SimpleRecord1.FirstItem'位置

是非法的。有没有一种方法可以创建检查,而不必创建实例并将代码放入函数或过程中?

为了使最后两条评论(Jere和Jim Rogers(更加具体,Ada方法实际上是定义列表元素的类型,以便任何类型的元素都可以放在同一列表中,并由同一类型的指针访问,而无需任何不可检查的转换。在OP的情况下,IMO最合适的方法是将所有列表元素标记为从同一抽象父类派生的记录,其中父类包含next、prev和priority组件。例如:

type List_Element;
type List_Ptr is access List_Element'Class;
type List_Element is abstract tagged record
Next, Prev : List_Ptr;
Priority   : Boolean;
end record;
type Simple_Record_1 is new List_Element with record
DoNotCare : Float;
end record;
type Simple_Record_2 is new List_Element with record
Rfc3092 : Boolean;
end record;

处理链表的SW处理指向list_Element类对象的list_Ptr值,但只显示通用组件Next、Prev和Priority。例如,当需要执行一些取决于列表元素实际类型的处理时,可以使用动态调度调用,也可以使用成员资格测试,然后进行类型转换,从list_Ptr获取到底层Simple_Record_1。

我会这么做,尤其是如果您要使用地址套印格式和/或UncheckedConversion

-----------------------------------------------------------------------------
type Header_Record is
record
First_Item  : Integer;
Second_Item : Boolean;
Third_item  : Integer;
end record
with Convention => C;

for Header_Record use
record
First_Item  at 0 range  0 .. 31;
Second_Item at 0 range 32 .. 47;
Third_Item  at 0 range 48 .. 79;
end record;

-----------------------------------------------------------------------------
type Item_Record_1 is
record
Header    : Header_Record;
DoNotCare : Float;
end record
with Convention => C;

for Item_Record_1 use
record
Header    at 0 range  0 .. 79;
DoNotCare at 0 range 80 .. 111;
end record;
--------------------------------------------------------------------------------
type Item_Record2 is
record
Header : Header_Record;
Rfc3092 : Boolean;
end record
with Convention => C;

for Item_Record2 use
record
Header  at 0 range  0 .. 79;
Rfc3092 at 0 range 80 .. 95;
end record;

-----------------------------------------------------------------------------

在这里,我们指定了确切的位布局。你需要使用一个级别的间接即,这有点痛苦

Item_Record1.Header.First_Item

然而,这应该是可行的。此外,永远记得使用

Convention => C

由于Ada记录布局和C结构布局可能会有很大的差异——这是意料之中的,因为Ada的语义丰富。

编辑:针对可移植性问题。尽管OP没有指定它必须是可移植的,但这仍然没有问题。。。

with Interfaces.C;
subtype int is Interfaces.C.int;
type Header_Record is
record
First_Item  : Interfaces.C.int;
Second_Item : Interfaces.C.int; --bool?
Third_item  : Interfaces.C.int;
end record
with Convention => C;

-- Exact values very likely to be different, for demo only
for Header_Record use
record
First_Item  at 0 range  0 .. int'Size;
Second_Item at 0 range  int'Size + 1 .. int'Size * 2;
Third_Item  at 0 range  int'Size * 2 + 1 .. int'Size * 3;
end record;

最新更新