使用 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
不对应于 Bit
。 0
对应的 8 位 ASCII Character
的位模式对应十进制值 48,而 1
的值为 49.
我认为你必须硬着头皮循环输入字符串。执行此操作的一个简单函数,要求输入字符串仅包含 0
s 和 1
s,可能是
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);
在从文件读取输入并尝试使用 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
不对应于 Bit
。 0
对应的 8 位 ASCII Character
的位模式对应十进制值 48,而 1
的值为 49.
我认为你必须硬着头皮循环输入字符串。执行此操作的一个简单函数,要求输入字符串仅包含 0
s 和 1
s,可能是
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);