问题描述
在C语言中,使用无符号char或int某种形式的位来表示非排他条件非常普遍,并且使用&|和〜运算符,非常高效。根据我有限的Ada经验,Ada中的等效内容将如以下代码所示。
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
type Colours is (Red,Green,Blue,Orange,Yellow,Purple);
type BitFieldType is array (Colours) of Boolean;
pragma Pack (BitFieldType);
RedBitField : constant BitFieldType := (Red => True,others => False);
GreenBitField : constant BitFieldType := (Green => True,others => False);
BlueBitField : constant BitFieldType := (Blue => True,others => False);
OrangeBitField : constant BitFieldType := (Orange => True,others => False);
YellowBitField : constant BitFieldType := (Yellow => True,others => False);
PurpleBitField : constant BitFieldType := (Purple => True,others => False);
NoColourBitField : constant BitFieldType := (others => False);
AllColoursBitField : constant BitFieldType := (others => True);
MyBitField : BitFieldType;
MyOtherBitField : BitFieldType;
Counter : Integer := 0;
begin
MyBitField := not RedBitField;
MyOtherBitField := RedBitField;
if (MyOtherBitField or MyBitField) = AllColoursBitField then
Counter := Counter + 1;
end if;
if (MyBitField and MyOtherBitField) = NoColourBitField then
Counter := Counter + 1;
end if;
Put_Line ("Counter is " & Integer'image (Counter));
end Main;
这看起来有些笨拙。是否有更好和更多的Lovelacey方法来使用像这样的位图?
解决方法
您实际尝试使用位域实现什么?您似乎想使用Ada编写C。如果是这样,请考虑在Ada中使用模块化类型,而在C中将使用无符号类型。
《 Ada 2012参考手册》第4.5.1节指出:
对于模块化类型,预定义的逻辑运算符在 逐位使用值的二进制表示形式 操作数产生结果的二进制表示形式,其中零 代表False,一个代表True。如果结果不在 类型的基本范围,模数的最终减法是 执行以将结果带入类型的基本范围。
阵列上的逻辑运算符在 每个组件都基于匹配的组件(就平等而言- 参见4.5.2),使用组件的预定义逻辑运算符 类型。结果数组的边界就是左操作数的边界。
例如,您示例的无符号类型可以定义为
type Color_Matrix is mod 2**6;
Red : constant Color_Matrix := 2#100000#;
Green : constant Color_Matrix := 2#010000#;
Blue : constant Color_Matrix := 2#001000#;
Orange : constant Color_Matrix := 2#000100#;
Yellow : constant Color_Matrix := 2#000010#;
Purple : constant Color_Matrix := 2#000001#;
No_Color : constant Color_Matrix := 0;
All_Colors : constant Color_Matrix := 2#111111#;
您现在可以在Color_Matrix实例上执行所有熟悉的操作。
编辑: 可以在https://sworthodoxy.blogspot.com/2014/03/ada-vs-c-bit-fields.html
中找到比较Ada表示子句和C / C ++位域的其他信息。 ,这确实取决于您要做什么。
通常,您会发现& | ~ << >>
运算符(有时甚至是&& ||
)的使用令人费解,并且在C中容易设置错误的掩码值用于设置,清除或测试单个位(例如,在BitFieldType中打开或关闭RED),而不是直接访问该位:
MyBitField(Red) := TRUE;
If MyBitField(Orange) then ...
很有趣的是,对于具有位设置,清除和测试指令的微控制器,编译器将C代码转换为显而易见的简单指令是一项艰巨的工作。
,我真的不应该花星期六做学生作业! ;-)
尝试将其尽可能移到声明部分。您可以这样做:
-- Warning: Not tested
with Ada.Text_IO;
procedure Bit_Fields is
type Typ_Counter is range 0 .. 1_000_000; -- Fix this!
package Counter_Io is new Ada.Text_Io.Integer_Io (Typ_Counter);
procedure Increment (Counter : in out Typ_Counter; On_Condition : Boolean) is
begin
if On_Condition then
Counter := Counter + 1; -- May overflow!
end if;
end Increment;
type Typ_Colour is mod 2**8 with Size => 8; -- Look into this!
Colour_Max : constant Typ_Colour := Typ_Colour'Last;
Colour_None : constant Typ_Colour := Typ_Colour'First;
type Knd_Colour is (Red,Green,Blue,Orange,Yellow,Purple);
type Arr_Colour is array (Knd_Colour) of Typ_Colour;
None : constant Arr_Colour := (others => Colour_None);
Max : constant Arr_Colour := (others => Colour_Max);
generic
with function Operation (Left,Right : Typ_Colour) return Typ_Colour;
function Generic_Operation (Left,Right : Arr_Colour) return Arr_Colour;
function Generic_Operation (Left,Right : Arr_Colour) return Arr_Colour
is
Result : Arr_Colour;
begin
for Gun in Result'Range loop
Result (Gun) := Operation (Left => Left (Gun),Right => Right (Gun));
end loop;
return Result;
end Generic_Operation;
function "or" is new Generic_Operation (Operation => "or");
function "and" is new Generic_Operation (Operation => "and");
My_Colours : Arr_Colour;
My_Other_Colours : Arr_Colour;
Counter : Typ_Counter := 0;
begin
My_Colours := (Red => not Colour_Max,others => Colour_None);
My_Other_Colours := (Red => Colour_Max,others => Colour_None);
Increment (Counter,On => (My_Other_Colours or My_Colours) = Max);
Increment (Counter,On => (My_Colours and My_Other_Colours) = None);
declare
use Ada.Text_Io,Counter_IO;
begin
Put ("Counter is ");
Put (Counter,Width => 0);
New_Line;
end;
end Bit_Fields;