使用 Unchecked_Conversion 读入值并转换为自定义类型

Using Unchecked_Conversion to read in values and convert to a custom type

在从文件读取输入并尝试使用 Unchecked_Conversion 时,我对 'Size'Component_Size 的工作方式感到很困惑。我知道要成功使用 Unchecked_Conversion,源和目标都需要相同 size。我正在从 000100000101001 之类的文件中读取输入,并希望使用未经检查的转换将其放入位数组中。但是,转换似乎总是失败,因为它们大小不同或太小。

    with Ada.Unchecked_Conversion;
    with Ada.Text_IO; use Ada.Text_IO;
    with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

    procedure main is
        type Bit is mod 2 with size => 1;
        type Bit_Array is array(Positive range <>) of Bit with pack;
        subtype Bit15 is Bit_Array(1 .. 15); //subtypes because can't use conversion on unconstrainted type
        subtype Bit11 is Bit_Array(1 .. 11);

        function StringA_to_Bit15 is
           new Ada.Unchecked_Conversion(source => String, target => Bit15);


        begin
        while not end_of_file loop
            declare
                s: String := get_line; //holding first line of input
                len: constant Natural := (if s'length-3 = 15 
                                        then 15
                                        else 11); 
                i: Integer;
                ba: Bit_Array(1 .. len); //constrain a Bit_Array based on length of input
            begin
                ba := String_to_Bit15(s);
                new_line;
            end;
        end loop;

这是我的类型,Bit 只能是 0 或 1,size 到 1 位。 Bit_Array 只是一个不受约束的位数组,因为我的输入可以是 15 位长或 11 位长。我的想法是将第一行读入一个字符串并将其转换为 Bit_Array。这行不通,因为 String 和所有其他基本类型都不是 Size => 1。所以自然而然地我想创建一个新类型来处理这个我尝试过的形式,创建我自己的 String 类型并设置 size => 1 但 Character 需要 8 位。我需要创建什么数据类型来读取一行数据并将其转换为 Bit_Array?我可能正在接近这个错误,但它让我很困惑。感谢任何帮助或提示!

您不能使用 Unchecked_Conversion,因为正如您所发现的,Character 不对应于 Bit0 对应的 8 位 ASCII Character 的位模式对应十进制值 48,而 1 的值为 49.

我认为你必须硬着头皮循环输入字符串。执行此操作的一个简单函数,要求输入字符串仅包含 0s 和 1s,可能是

function To_Bit_Array (S : String) return Bit_Array is
   Input : constant String (1 .. S'Length) := S;
   Result : Bit_Array (1 .. S'Length);
begin
   for J in Input'Range loop
      Result (J) := (case Input (J) is
                        when '0' => 0,
                        when '1' => 1,
                        when others => raise Constraint_Error);
   end loop;
   return Result;
end To_Bit_Array;

Input 声明的要点是确保两个数组的索引 J 相同;String 的第一个索引只需Positive,即大于0)。

但是,如果您要从模块化整数类型转换为位数组,则可以使用 Unchecked_Conversion。我通常避免使用 Unchecked_Conversion 除非作为最后的手段,但我可以看到从整数转换为位数组类型的诱惑。但是,我也会考虑是否只使用模块化整数,因为它也可以用于按位运算。不过,使用数组语法访问位是一个不错的功能。即使我想将模块化整数转换为位数组,我仍然建议尽可能避免使用 Unchecked_Conversion,或者 Ada 中几乎所有的 Unchecked_ 任何东西。 一个原因是 Unchecked_Conversion 可能不太便携。 例如,不同的编译器和不同的目标可能会以不同的顺序存储这些位。

另一个建议是使用布尔数组,而不是 而不是打包的位数组。内存中的存储看起来应该是一样的, 但我认为您会发现使用布尔值比位更方便。它使您不必将值与 1 或 0 进行比较。

因此,将输入字符串转换为模块化整数的一种方法是使用 Ada.Text_IO.Modular_IO 包。

type Short is mod 2**16;

package Short_IO is new Modular_IO (Num => Short);

type Bit_Array is array (Positive range <>) of Boolean
  with Component_Size => 1;
...

declare
     Input : constant String := Get_Line;
     Value : Short := 0;
     Last  : Positive;
     Bits_11 : Bit11;

     -- Instead of using Unchecked_Conversion, consider writing a 
     -- simple conversion function
     --
     function To_Bit11 (Value : Short) return Bit11 is
        ((for I in Bit11'Range => (Short(2**(I-1)) and Value) /= 0));

  begin

     --  Enclosing the input string with 2#{binary_string}#, 
     --  causes the number to be read in base 2, as a binary text
     --  string.
     Short_IO.Get (From  => "2#" & Input & "#",
                   Item  => Value,
                   Last  => Last);

     --  You could use unchecked conversion here to convert
     --  to the Bit array, but I'd recommend doing this
     --  without using unchecked features of the language
     --  e.g. using a simple loop

     for I in Bits_11'Range loop
        Bits_11 (I) := (Short(2**(I-1)) and Value) /= 0;
     end loop;

     --  or you can even try an Ada 2020 feature that already has
     --  been implemented in the latest community edition of GNAT.
     --  By assigning a new form of array aggregate to the 
     --  bit array object. You'd need to set the -gnatX compiler
     --  option to tell the compiler to use Ada extended 2020
     --  features. Many Ada 2020 features are not yet available to try
     --  out, but this one is available.

     Bits_11 :=
        (for I in Bits_11'Range => (Short (2**(I-1)) and Value) /= 0);

     -- or combine this into an expression function like above,
     -- then you have a function similar to the one you'd get using
     -- Unchecked_Conversion, except more portable, and one can
     -- examine the code to understand the implementation.

     Bits_11 := To_Bit11 (Value);