来自另一个过程中的过程调用的输出不一致

时间:2014-05-01 01:47:57

标签: procedure ada

我遇到了来自另一个程序中调用的过程的输出不一致的问题。以下是相对简单的哈希程序的简化版本。

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Conversion;
with Ada.Strings; use Ada.Strings;

procedure lab5_C_Part_A is

package LongIntIO is new Ada.Text_IO.Integer_IO(Long_Integer);
use LongIntIO;

package IntIO is new Ada.Text_IO.Integer_IO(Integer);
use IntIO;

type String2 is new String(1..2);
type String16 is new String(1..16);

function ConvertChar is
    new Ada.Unchecked_Conversion(Character, Integer);

function ConvertString2 is 
    new Ada.Unchecked_Conversion(String2, Integer);

table: array(1..128) of String16:= (others => "                ");

function hash(key: in String16) return Integer is
A: String2:= String2(key(15..16));
begin
    return ((((ConvertChar(key(1)) + ConvertChar(key(10))) * 512) + ConvertString2(A)) / 256) mod 128;
end hash;

procedure linearProbe(key: in String16; index, probes: out Integer) is 
begin
    probes:= 1;
    index:= hash(key);
    put("inside method linearProbe() : "); put(index); new_line;
    while true loop
        if table(index) = key then put("key found"); new_line; exit;
        elsif table(index) = "                " then put("empty found"); new_line; exit;
        else
            index:= index + 1;
            if index > table'Length then
            index:= 1;
            end if;
        put("incrementing"); new_line;
        end if;
        probes:= probes + 1;
    end loop;
end linearProbe;

index: Integer:= 1;
probes: Integer:= 1;

begin
    put("outside method linearProbe() : "); put(hash("Afterwards      ")); 
    new_line;    
    linearProbe("Afterwards      ", index, probes);
    put("index: "); put(index); new_line;
    put("probes: "); put(probes); new_line;
end;

程序多次运行时的输出如下所示:

kcg@hardmode-activated:~/ada/lab5 test > gnatmake lab5_C_Part_A
gcc-4.6 -c lab5_C_Part_A.adb
lab5_C_Part_A.adb:5:11: warning: file name does not match unit name, should be "lab5_c_part_a.adb"
lab5_C_Part_A.adb:16:01: warning: types for unchecked conversion have different sizes
lab5_C_Part_A.adb:19:01: warning: types for unchecked conversion have different sizes
gnatbind -x lab5_C_Part_A.ali
gnatlink lab5_C_Part_A.ali
kcg@hardmode-activated:~/ada/lab5 test > ./lab5_C_Part_A
outside method linearProbe() :           8
inside method linearProbe() :           8
empty found
index:           8
probes:           1
kcg@hardmode-activated:~/ada/lab5 test > ./lab5_C_Part_A
outside method linearProbe() :           9
inside method linearProbe() :           8
empty found
index:           8
probes:           1
kcg@hardmode-activated:~/ada/lab5 test > ./lab5_C_Part_A
outside method linearProbe() :           8
inside method linearProbe() :           8
empty found
index:           8
probes:           1
kcg@hardmode-activated:~/ada/lab5 test > ./lab5_C_Part_A
outside method linearProbe() :           9
inside method linearProbe() :           8
empty found
index:           8
probes:           1

我想知道为什么会这样,但如果有人能告诉我他们是否得到与我相同的输出,我会很高兴。

如果您需要更多信息,请告诉我们。

1 个答案:

答案 0 :(得分:3)

Unchecked_Conversion的目的是读取声明为一种类型的数据,就好像存储在内存中的位是不同类型的数据一样。只有当这两种类型具有相同的尺寸(RM 13.9(6))时,才能保证工作正常。

这种情况特别有问题:

function ConvertString2 is 
    new Ada.Unchecked_Conversion(String2, Integer);

String2是16位; {Ad}实现的大小Integer可能会有所不同,但根据警告,编译器可能是32位。问题是这个Unchecked_Conversion可以简单地通过获取数据的地址并在该地址读取32位整数来实现。由于源只有16位,程序将尝试读取不属于该对象的数据。如果额外的数据未初始化,或者堆栈上的某些内容可能取决于之前运行的程序,结果可能会不一致。 (如果额外数据实际上在分配给程序的内存空间之外,您也可能会遇到程序错误。根据处理器的不同,如果源不是4字节对齐的话,执行此类操作可能会导致对齐错误。 )

要正确执行此操作,您应该定义一个与String2大小相同的整数类型:

type String2_Int is range -(2**(String2'Size-1)) .. 2**(String2'Size-1) - 1;
for String2_Int'Size use String2'Size;

实际上是

type String2_Int is range -32768 .. 32767;
for String2_Int'Size use 16;

此外,最好指定String2

的对齐方式
for String2'Alignment use 16;

如果您在需要16位整数读取的处理器上运行,则需要在2字节边界上运行。现在:

function ConvertString2 is 
    new Ada.Unchecked_Conversion(String2, String2_Int);

如果您想生成Integer,首先使用上面的内容转换为String2_Int,然后使用普通类型转换(而不是{{} 1}})将Unchecked_Conversion转换为String2_Int

你可以在这里做同样的转变:

Integer

但是没有必要,因为function ConvertChar is new Ada.Unchecked_Conversion(Character, Integer); 会给你你想要的东西,可能(它返回0 ... 255范围内的结果;如果你想要-128 .. 127范围内的东西,那么未经检查的转换为带符号的8位类型是可行的,或者您可以自己进行数学计算。您也可以放弃Character'Pos(c)上的Unchecked_Conversion,只需对两个字符中的每个字符使用String2,然后将结果合并为

Character'Pos

或类似的东西。