更改数组类型:8位类型到6位类型

时间:2015-12-04 05:31:15

标签: bit ada

我在file.ads中有两种类型和两种类型的数组

 type Ebit is mod 2**8;
 type Sbit is mod 2**6;
 type Data_Type is array (Positive range <>) of Ebit;
 type Changed_Data_Type is array (Positive range <>) of Sbit;

和功能:

function ChangeDataType (D : in Data_Type) return Changed_Data_Type
 with
   Pre => D'Length rem 3 = 0 and D'Last < Positive'Last / 4,
 Post => ChangeDataType'Result'Length = 4 * (D'Length / 3)

好的我能理解这一切。 例如,我们有以下数组:

8位值函数中的65,66,65,65,66,65应该以6位值给出16,20,9,1,16,20,9,1。

我不知道如何从8位表构建一个6位表。

我对sollutions的想法是例如从类型中逐渐采取:

fill all bites in 6bit type to 0 (propably default)
if first bit (2**1) is 1 set bit (2**1) in 6bit type to 1;
and do some iterations

但我不知道怎么做,总是类型问题。这是个好主意还是我可以用更简单的方式做到这一点?我花了最后一个尝试写这个但没有成功。

编辑: 我写了一些代码,它的工作原理但我的数组初始化有问题。

function ChangeDataType (D: in Data_Type) return Changed_Data_Type
 is
  length: Natural := (4*(D'Length / 3));
  ER: Changed_Data_type(length);
  Temp: Ebit;     
  Temp1: Ebit;
  Temp2: Ebit;
  Actual: Ebit;
  n: Natural;
  k: Natural;
begin
  n := 0;
  k := 0;
  Temp := 2#00000000#;
  Temp1 := 2#00000000#;
  Temp2 := 2#00000000#;

  Array_loop:
  for k in D'Range loop
     case n is
        when 0 =>
           Actual := D(k);
           Temp1 := Actual / 2**2;
           ER(k) := Sbit(Temp1);
           Temp := Actual * ( 2**4);
           n := 2; 
        when 2 =>
           Actual := D(k);
           Temp1 := Actual / 2**4;
           Temp2 := Temp1 or Temp;
           ER(k) := Sbit(Temp2);
           Temp := Actual * ( 2**2); 
           n := 4;
        when 4 =>
           Actual := D(k);
           Temp1 := Actual / 2**6;
           Temp2 := Temp1 or Temp;
           ER(k) := Sbit(Temp2);
           n := 6;
        when 6 =>
           Temp1 := Actual * ( 2**2);
           Temp2 := Actual / 2**2;
           ER(k) := Sbit(Temp2);
           n := 0;
        when others =>
           n := 0;
     end case;
  end loop Array_Loop;


  return ER;
 end;

1 个答案:

答案 0 :(得分:1)

如果我理解你要问的是什么......你想要将相同的8位数据重新打包成6位数值,以便&#34;剩余的&#34;第一个EBit的位成为第二个Sbit的第一位(最高或最低?)。

一种方法可以做到这一点 - 至少对于固定大小的数组,例如您的6个字* 8位,8个字* 6位示例,是通过使用打包指定每个数组类型的内存中的确切布局,以及representation aspects(或者在Ada-2012之前的编译指示){{3 }}

我还没有测试过以下内容,但它可以作为一个起点。

 type Ebit is mod 2**8;
 type Sbit is mod 2**6;
 for Ebit'Size use 8;
 for Sbit'Size use 6;
 type Data_Type is array (1 .. 6) of Ebit
    with Alignment => 0;  -- this should pack tightly
 type Changed_Data_Type is array (1 .. 8) of Sbit
    with Alignment => 0;

然后,您可以使用两种数组类型实例化通用Unchecked_Conversion函数,并使用该函数从一个数组转换为另一个数组。

 with Ada.Unchecked_Conversion;
 function Change_Type is new Ada.Unchecked_Conversion(Data_Type, Changed_Data_Type);

 declare
   Packed_Bytes : Changed_Data_Type := Change_Type(Original_Bytes);
 begin ...

就生成的代码而言,它并不慢,因为Unchecked_Conversion没有做任何事情,除了告诉编译时类型检查以另一种方式查看。

我将Unchecked_Conversion视为&#34;我打算这样做&#34;看着我的猫从窗台上掉下来后给了我。再次...

或者,如果您希望避免复制,可以将Original_Bytes声明为别名,并使用类似的访问类型和Unchecked_Access技巧将两个数组覆盖在同一内存中(如C中的Union)。我认为这就是DarkestKhan所说的&#34;阵列叠加&#34;在下面的评论中。另见nicely described here的第3节,其中进一步描述了该技术。它指出,重叠变量不仅必须声明为aliased,还必须声明volatile,以便对一个视图的访问不会优化到寄存器中,而是反映通过另一个视图所做的任何更改。覆盖的另一种方法是this rather dated page

现在,这可能容易受到字符串考虑因素的影响,即它可能在某些平台上运行,但在其他平台上却无法运行。上面的第二个参考给出了一个具有其成员的精确位对齐的记录的示例:我们至少可以采用Bit_Order方面,如with Alignment => 0, Bit_Order => Low_Order_First;中对于上面的数组...

-- code stolen from "Rationale" ... see link above p.11
type RR is record
      Code: Opcode;
      R1: Register;
      R2: Register;
end record
with Alignment => 2, Bit_Order => High_Order_First;

for RR use record
      Code at 0 range 0 .. 7;
      R1 at 1 range 0 .. 3;
      R2 at 1 range 4 .. 7;
end record;

我不清楚的一件事是,是否有一种公式化的方法来指定数组中每个元素的确切布局,就像在此处的记录中所做的那样 - 或者即使有&#39;潜在的需要。如有必要,一种解决方法是用记录替换上面的数组。但如果有的话,我很乐意看到更好的答案。