Использование Unchecked_Conversion для чтения значений и преобразования в пользовательский тип - PullRequest
2 голосов
/ 26 марта 2019

Я не совсем понимаю, как работают 'Size и 'Component_Size при чтении ввода из файла и попытке использовать Unchecked_Conversion.Я знаю, что для успешного использования Unchecked_Conversion и Источник, и Цель должны быть одинаковыми size.Я читаю входные данные из файла типа 000100000101001 и хочу использовать Unchecked Conversion, чтобы поместить его в массив битов.Однако преобразование всегда кажется неудачным из-за того, что они не имеют одинаковый размер или слишком малы.

    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;

Вот мои типы, Бит, который может быть только 0 или 1 с size до 1 бита,Bit_Array - это просто массив битов, который не ограничен, потому что мой ввод может быть длиной 15 бит или длиной 11 бит.Я думал просто прочитать в первой строке строку и преобразовать ее в Bit_Array.Это не работает, потому что String и любой другой тип примитива не Size => 1.Естественно, я бы хотел создать новый тип для обработки этого, который я пробовал в форме, создав собственный тип String и установив size => 1, но символ требует 8-бит.Какой тип данных мне нужно создать, чтобы прочитать строку данных и преобразовать ее так, чтобы она соответствовала Bit_Array?Возможно, я подхожу к этому неправильно, но это очень смущает меня.Любая помощь или советы приветствуются!

Ответы [ 2 ]

5 голосов
/ 26 марта 2019

Вы не можете использовать Unchecked_Conversion, потому что, как вы обнаружили, Character не соответствует Bit.8-битный ASCII Character, соответствующий 0, имеет битовую комбинацию, соответствующую десятичному значению 48, а 1 имеет значение 49.

Я думаю, вам придется кусать пулю и зацикливатьсячерез строку ввода.Простая функция для этого, требующая, чтобы входная строка состояла только из 0 с и 1 с, могла бы быть

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).

0 голосов
/ 28 марта 2019

Однако вы можете использовать Unchecked_Conversion, если вы конвертируете, скажем, из модульного целочисленного типа в битовый массив.Я обычно избегаю использования Unchecked_Conversion, если не в крайнем случае, но я вижу искушение преобразовать целочисленный тип в битовый массив.Тем не менее, я бы также подумал, стоит ли просто использовать модульное целое число, поскольку его можно использовать и для побитовых операций.Однако использование синтаксиса массива для доступа к битам - хорошая функция.Даже если бы я захотел преобразовать модульное целое число в битовый массив, я все равно рекомендовал бы по возможности избегать использования Unchecked_Conversion или значительной части Unchecked_ что-либо в Ada.Одна из причин заключается в том, что 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);
...