我有一个带有 2 个值的 Ada 枚举type Polarity is (Normal, Reversed)
,我想将它们分别转换为 0、1(或 True、False——因为布尔值似乎隐含地像二进制一样好),所以我可以将它们的值作为特定位存储在字节。我怎样才能做到这一点?
5 回答
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
一个简单的方法是查找表:
Bool_Polarity : constant Array(Polarity) of Boolean
:= (Normal=>False, Reversed => True);
然后将其用作
B Boolean := Bool_Polarity(P);
当然,使用 'Pos 属性并没有错,但是 LUT 使映射变得可读且非常明显。
由于它是恒定的,您希望它在恒定折叠阶段优化掉,并且似乎:我已经使用类似的技巧为 AVR 编译具有非常可接受的可执行文件大小(低至 0.6k 以独立驱动 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 你也可以安全地向上转换为Integer
orNatural
或Positive
。您还可以使用相同的技术直接访问/从 32 位整数到/从 32 位记录类型。
这里有两点:
1) 枚举已经存储为 binary。一切都是。特别是,如上所述,您的枚举将存储为0
forNormal
和1
for Reversed
,除非您特意告诉编译器使用其他值。
如果您想从枚举中获取该值Integer
而不是枚举值,您有两种选择。该'pos()
属性将为该枚举在枚举中的位置返回一个从 0 开始的数字,Unchecked_Conversion
并将返回计算机为其存储的实际值。(值没有区别,除非使用了枚举表示子句)。
2)枚举很好,但不要重新发明Boolean
。如果您的枚举只能有两个值,那么您不会通过自定义枚举获得任何有用的信息,并且会丢失很多有用的属性Boolean
。布尔值可以直接从循环和if
检查中选择。布尔值为它们定义了and
, or
,xor
等。可以将布尔值放入打包数组中,然后在整个数组中按位定义这些相同的运算符。
我的一个特殊的烦恼是人们最终定义了一个自定义布尔值,逻辑反转(所以它的真实条件是 0)。如果你这样做,Ada Lovelace的鬼魂将从坟墓里回来,并迫使你听详尽的解释如何用差分机计算伯努利序列。不要让这种事情发生在你身上!
因此,如果拥有第三个枚举值永远没有意义,您只需将对象命名为适当描述True
条件的名称(例如Reversed_Polarity : Boolean;
:),然后继续您的快乐方式。
似乎我需要做的就是pragma Pack([type name]);
(其中“类型名称”是由极性组成的类型)将值压缩到一个位。