给出一个非常简单的SPARK函数,它对一个整数数组求和:
function Add (X, Y : in Ints) return Ints is
Sum : Ints;
begin
for i in Ints'Range loop
pragma Loop_Invariant (for all j in Ints'First .. i - 1 => Sum(j) = X(j) + Y(j)); -- line 7
Sum(i) := X(i) + Y(i);
end loop;
return Sum; -- line 11
end Add;
(type Ints is array (Integer range 0 .. 9) of Integer_32
)
没有循环不变的编译工作正常(因为我有一个前提条件,它限制X
和Y
的元素,这样就不会发生溢出。但是,为了显示post条件的某些属性,我需要不变量,但结果是:
7:69: warning: "Sum" may be referenced before it has a value
Phase 2 of 3: analysis and translation to intermediate language ...
7:10: "Sum" is not initialized
11:7: warning: "Sum" might not be initialized
我不确定"初始化的概念"用证明语言表达,所以我不知道如何说服gnatprove没有发生未初始化的读数。
我可以通过在功能开始时将Sum
的所有元素明确设置为零来删除警告,但我希望有更好的方法。
答案 0 :(得分:4)
在SPARK中,数组被视为整个对象,并且不允许像您一样进行逐个组件的初始化。但是,gnatprove中有一个启发式方法,允许在数组范围内进行简单的for循环,就像你一样。这就是为什么没有循环不变量,你就不会收到警告。这种启发式方法因循环不变而崩溃,这就是为什么你再次收到警告的原因。
您必须使用编译指示警告接受警告,如下所述:
https://gcc.gnu.org/onlinedocs/gnat_rm/Pragma-Warnings.html
为了避免你在第7行得到的错误,你可以在赋值后移动循环不变量(并相应地改变量化的范围)。