5

我有一个带有 2 个值的 Ada 枚举type Polarity is (Normal, Reversed),我想将它们分别转换为 0、1(或 True、False——因为布尔值似乎隐含地像二进制一样好),所以我可以将它们的值作为特定位存储在字节。我怎样才能做到这一点?

4

5 回答 5

3

3.5.5 离散类型的操作包括function S'Pos(Arg : S'Base)“返回 的值的位置编号Arg,作为通用整数类型的值”。因此,

Polarity'Pos(Normal) = 0
Polarity'Pos(Reversed) = 1

您可以使用13.4 枚举表示子句更改编号。

...而且当然:

Boolean'Val(Polarity'Pos(Normal)) = False
Boolean'Val(Polarity'Pos(Reversed)) = True
于 2012-12-04T02:44:56.267 回答
3

一个简单的方法是查找表:

Bool_Polarity : constant Array(Polarity) of Boolean 
              := (Normal=>False, Reversed => True);

然后将其用作

 B Boolean := Bool_Polarity(P);

当然,使用 'Pos 属性并没有错,但是 LUT 使映射变得可读且非常明显。

由于它是恒定的,您希望它在恒定折叠阶段优化掉,并且似乎:我已经使用类似的技巧为 AVR 编译具有非常可接受的可执行文件大小(低至 0.6k 以独立驱动 2 个步进电机)

于 2012-12-04T10:25:04.950 回答
2

我认为您正在寻找的是带有表示子句的记录类型:

procedure Main is

   type Byte_T is mod 2**8-1;
   for Byte_T'Size use 8;

   type Filler7_T is mod 2**7-1;
   for Filler7_T'Size use 7;

   type Polarity_T is (Normal,Reversed);
   for Polarity_T use (Normal => 0, Reversed => 1);
   for Polarity_T'Size use 1;

   type Byte_As_Record_T is record
      Filler   : Filler7_T;
      Polarity : Polarity_T;
   end record;

   for Byte_As_Record_T use record
      Filler at 0 range 0 .. 6;
      Polarity at 0 range 7 .. 7;
   end record;
   for Byte_As_Record_T'Size use 8;

   function Convert is new Ada.Unchecked_Conversion
     (Source => Byte_As_Record_T,
      Target => Byte_T);

   function Convert is new Ada.Unchecked_Conversion
     (Source => Byte_T,
      Target => Byte_As_Record_T);

begin

   -- TBC
   null;

end Main;

由于Byte_As_Record_T&Byte_T的大小相同,您可以使用它unchecked conversion来安全地在类型之间进行转换。

的表示子句Byte_As_Record_T允许您指定放置哪些位/字节polarity_t。(我选择了第 8 位)

我的定义Byte_T可能不是你想要的,但只要它是 8 位长,这个原则应该仍然可行。从 Byte_T 你也可以安全地向上转换为IntegerorNaturalPositive。您还可以使用相同的技术直接访问/从 32 位整数到/从 32 位记录类型。

于 2012-12-04T09:05:50.917 回答
1

这里有两点:

1) 枚举已经存储为 binary。一切都是。特别是,如上所述,您的枚举将存储为0forNormal1for Reversed,除非您特意告诉编译器使用其他值。

如果您想从枚举中获取该值Integer而不是枚举值,您有两种选择。该'pos()属性将为该枚举在枚举中的位置返回一个从 0 开始的数字,Unchecked_Conversion并将返回计算机为其存储的实际值。(值没有区别,除非使用了枚举表示子句)。

2)枚​​举很好,但不要重新发明Boolean。如果您的枚举只能有两个值,那么您不会通过自定义枚举获得任何有用的信息,并且会丢失很多有用的属性Boolean。布尔值可以直接从循环和if检查中选择。布尔值为它们定义了and, or,xor等。可以将布尔值放入打包数组中,然后在整个数组中按位定义这些相同的运算符。

我的一个特殊的烦恼是人们最终定义了一个自定义布尔值,逻辑反转(所以它的真实条件是 0)。如果你这样做,Ada Lovelace的鬼魂将从坟墓里回来,并迫使你听详尽的解释如何用差分机计算伯努利序列。不要让这种事情发生在你身上!

因此,如果拥有第三个枚举值永远没有意义,您只需将对象命名为适当描述True条件的名称(例如Reversed_Polarity : Boolean;:),然后继续您的快乐方式。

于 2012-12-04T19:00:05.033 回答
0

似乎我需要做的就是pragma Pack([type name]);(其中“类型名称”是由极性组成的类型)将值压缩到一个位。

于 2012-12-07T14:07:30.557 回答