我仍然是Ada的新手,我认为我误解了Preconditions的使用,因为通过GNAT RM查看似乎检查不会在运行时执行。此外,Precondition here的GNAT RM没有指定如果不满足前提条件则抛出哪个异常。
以下是我正在尝试的代码:
procedure Test is
begin
generic
type Element_Type is private;
use System.Storage_Elements;
procedure Byte_Copy (Destination : out Element_Type;
Source : in Element_Type;
Size : in Storage_Count := Element_Type'Size)
with Pre =>
Size <= Destination'Size and
Size <= Source'Size;
procedure Byte_Copy (Destination : out Element_Type;
Source : in Element_Type;
Size : in Storage_Count := Element_Type'Size)
is
subtype Byte_Array is Storage_Array (1 .. Size / System.Storage_Unit);
Write, Read : Byte_Array;
for Write'Address use Destination'Address;
for Read'Address use Source'Address;
begin
Ada.Text_IO.Put_Line("Size to copy =" & Size'Img &
" and Source'Size =" & Source'Size'Img);
if Size > Destination'Size or else Size > Source'Size then
raise Constraint_Error with
"Source'Size < Size or else > Destination'Size";
end if;
for N in Byte_Array'Range loop
Write (N) := Read (N);
end loop;
end Byte_Copy;
procedure Integer_Copy is new Byte_Copy(Integer);
use type System.Storage_Elements.Storage_Count;
A, B : Integer;
begin
A := 5;
B := 987;
Ada.Text_IO.Put_Line ("A =" & A'Img);
Ada.Text_IO.Put_Line ("B =" & B'Img);
Integer_Copy (A, B, Integer'Size / 2);
Ada.Text_IO.Put_Line ("A = " & A'Img);
Ada.Text_IO.Put_Line ("B = " & B'Img);
Integer_Copy (A, B, Integer'Size * 2);
Ada.Text_IO.Put_Line ("A =" & A'Img);
Ada.Text_IO.Put_Line ("B =" & B'Img);
end Test;
如果我理解正确,那么在调用Put_Line过程之前,该程序应该引发一些未指定的异常。但是你可以看到,当我运行程序时,使用无效的Size参数调用该过程,该参数违反了Precondition Destination'Size ≥ Size ≤ Source'Size
。相反,我必须放置一个if
语句来实际捕获错误并引发异常Constraint_Error以保持理智。
$ ./test
A = 5
B = 987
Size to copy = 16 and Source'Size = 32
A = 987
B = 987
Size to copy = 64 and Source'Size = 32
raised CONSTRAINT_ERROR : Source'Size < Size or else > Destination'Size
我尝试了添加pragma Precondition ( ... )
之类的变体,但这也不起作用。
一个奇怪的事情是,如果我在通用过程体/定义中重复with Pre =>
子句,程序实际上会编译。它通常不允许这个过程并引发错误(即,前提条件应仅在正式声明中,而不是在定义中)。在这种情况下,通用程序是例外吗?
我也很惊讶use子句可以添加到通用过程声明中。这使得定义形式参数名称更容易(那些长度非常长)但看起来更像是一个bug,因为这不能用于正常/常规过程声明。
P.S。为了学习目的,我希望用Ada语言实现我最近可能的模仿memcpy()的方法。
答案 0 :(得分:6)
您需要通过使用-gnata
编译来启用断言:
$ gnatmake -gnat12 -gnata test.adb
gcc -c -gnat12 -gnata test.adb
gnatbind -x test.ali
gnatlink test.ali
gnatlink: warning: executable name "test" may conflict with shell command
$ ./test
A = 5
B = 987
Size to copy = 16 and Source'Size = 32
A = 987
B = 987
raised SYSTEM.ASSERTIONS.ASSERT_FAILURE : failed precondition from test.adb:13 instantiated at test.adb:39
在FSF GNAT&lt; = 4.8中没有实现Pragma Assertion_Policy(好吧,你不能用它来打开或关闭检查)。但是, 在GNAT GPL 2013中实现;如果您不使用GNAT项目文件,则意味着创建包含
的文件gnat.adc
pragma Assertion_Policy (Check);
次要问题:'Size
是位,而不是字节,所以Storage_Count
实际上不是正确的类型!