我遇到了来自另一个程序中调用的过程的输出不一致的问题。以下是相对简单的哈希程序的简化版本。
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
我想知道为什么会这样,但如果有人能告诉我他们是否得到与我相同的输出,我会很高兴。
如果您需要更多信息,请告诉我们。
答案 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
或类似的东西。