Ada:组件与父级重叠的派生记录

标签 ada

我正在尝试为两个密切相关的不同设备定义硬件接口(interface),但一个设备的功能比另一个设备稍多。

作为问题的一个非常简化的版本,让我们说:

  • 设备 A 有 2 个寄存器:R0 未使用,R1 已使用
  • 设备 B 有 2 个寄存器:同时使用 R0 和 R1

我试图通过多态定义重用代码和定义,例如:

   Tag_Length : constant := Standard'Address_Size / System.Storage_Unit;

   type A_IO is tagged record
      --  RO precedes, is unused but the space is reserved
      R1 : Byte;
   end record;
   for A_IO use record
      R1 at Tag_Length + 1 range 0 .. 7;
   end record;
   
   type B_IO is new A_IO with record
      R0 : Byte;
      --  R1 would follow as defined by the parent record
   end record;
   for B_IO use record
      R0 at Tag_Length + 0 range 0 .. 7;
   end record;

这会导致编译器错误,在大多数情况下都有意义:组件与“B_IO”的父字段重叠(GNAT 社区 2019)。

我有替代方案,其中涉及:

  • 为每个设备使用相同的类型(缺点:设备 A 将看到不应可见的组件)
  • 使用完全不同的类型,在使用共享代码时通过访问类型依靠未经检查的转换来更改对象的 View (缺点:将涉及多次重新定义某些相同的组件)

我想知道是否有一种可行的方法,没有任何提到的缺点。

最佳答案

我不知道这是否是一个错误。在7.1和7.2系列中它编译得很好,但在8.2和9.1中它无法编译。

由于您愿意使用标记记录并让标记占用位布局中的空间,因此潜在的解决方法是使用变体未标记记录并用变体替换标记。考虑:

type Record_Select is (A_IO, B_IO);
type Shared_Record(S : Record_Select) is record
    R1 : Byte;
    case S is
        when A_IO => null;
        when B_IO => R0 : Byte;
    end case; 
end record;
for Shared_Record use record
    S  at 0 range 0 .. 15;
    R0 at 2 range 0 .. 7;
    R1 at 3 range 0 .. 7;
end record;
for Shared_Record'Size use 32;

您可以调整尺寸以匹配您的实际标签尺寸。我只是添加了一些值。这将为您提供与标记记录类似的布局(当然减去大小差异)。

此外,如果您将变体参数设置为具有默认值,则可以在两个变体之间进行复制,而无需未经检查的转换,只要您在类型中没有变体约束的情况下定义它们即可:

   type Record_Select is (A_IO, B_IO);

   -- Note the default value for S
   type Shared_Record(S : Record_Select := B_IO) is record
      R1 : Byte;
      case S is
         when A_IO => null;
         when B_IO => R0 : Byte;
      end case; 
   end record;
   for Shared_Record use record
      S  at 0 range 0 .. 15;
      R0 at 2 range 0 .. 7;
      R1 at 3 range 0 .. 7;
   end record;
   for Shared_Record'Size use 32;

   -- Note the unconstrained type definitions
   A : Shared_Record := (S => A_IO, R1 => 3);
   B : Shared_Record := (S => B_IO, R0 => 1, R1 => 2);
begin
   Put_Line(B.R1'Image);
   B := A;
   Put_Line(B.R1'Image);

输出:

 2
 3

关于Ada:组件与父级重叠的派生记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64001010/

相关文章:

ada - IF 语句中的 "and"与 "and then"之间有区别吗

ada - "Subtype mark required in this context"到底是什么?

xcode - 如何在 Mac OS X 上获取内存泄漏的行号堆栈跟踪?

string - 如何从 Ada 中的其他字符串构建字符串?

makefile - 尽管安装了 gfortran,但找不到 -lgfortran

ada - 通过点运算符调用原始操作失败

ada - SPARK 整数溢出检查

ada - 如何在多维数组中使用for循环?

types - Ada——什么是模块化类型

c++ - 管道到/从 Ada 程序到 C++ 程序