我有两条记录,其中一些字段需要在每条记录中的相同位置。尽管代码中对此进行了大量注释,但在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;