为什么 GNAT 拒绝具有默认判别值的数组类型?
Why does GNAT reject an array type with a default discriminant value?
此(声明)代码引发存储错误:
type Vector is array (Integer range <>) of Integer;
type Array_Starting_At_One (Max : Integer := 0) is
record
Mat : Vector (1 .. Max);
end record;
X : Array_Starting_At_One;
我不明白为什么。如果我指定默认值,如在 X : Array_Starting_At_One (Max => 0);
中,错误消失,尽管 Array_Starting_At_One 类型规范仍然触发警告,创建此类对象可能会引发 Storage_Error.
我什至没有尝试存储一个位,所以这个错误对我来说没有任何意义:
raised STORAGE_ERROR : System.Memory.Alloc: object too large
当然,任何索引范围为 1..Integer'Last 的数组都可以引发 Storage_Error。编译器警告您这种可能性。尝试限制数组类型的索引范围,例如:
subtype Indices is Integer range 0..1024;
type Vector is Array (Indices range <>) of Integer;
type Array_Ending_At (Max : Indices := 0) is
record
Mat : Vector(1..Max);
end record;
当使用默认判别式声明变量时,以后可以通过赋值更改判别式。这意味着编译器(至少 GNAT 这样做)将分配(在堆栈上)足够的空间来容纳具有最大允许值(在这种情况下为 Integer'Last)的任何判别式的对象。
要么增加筹码量(不一定推荐),要么使用更适合您问题的不同子类型:
subtype Foo is Integer range 1..10;
type Vector is array (Foo range <>) of Integer;
如您所见,这是一个编译器问题。 Janus/Ada 编译器会毫无怨言或 run-time 例外地接受您的代码。
你的变量X
是一个不受约束的对象;判别式(以及对象的大小)可以通过 full-record 赋值来改变。 ARM 对如何实现这些事情保持沉默。 GNAT 已选择分配足够的 space 以获得最大可能的价值;由于 X
是在堆栈上分配的,因此使用 GNAT 的默认堆栈大小将没有足够的 space (如果您在堆上分配它,您可能没有问题)。 Janus 只为当前值分配足够的 space,这可能导致 X.Mat
被隐式分配到堆上。
Janus 方式更 developer-friendly 并且对于大多数应用程序来说都是可以接受的,开发人员不关心东西分配在哪里,但是有些情况下隐式堆分配是不能接受的,所以 GNAT 方式是更一般。
此(声明)代码引发存储错误:
type Vector is array (Integer range <>) of Integer;
type Array_Starting_At_One (Max : Integer := 0) is
record
Mat : Vector (1 .. Max);
end record;
X : Array_Starting_At_One;
我不明白为什么。如果我指定默认值,如在 X : Array_Starting_At_One (Max => 0);
中,错误消失,尽管 Array_Starting_At_One 类型规范仍然触发警告,创建此类对象可能会引发 Storage_Error.
我什至没有尝试存储一个位,所以这个错误对我来说没有任何意义:
raised STORAGE_ERROR : System.Memory.Alloc: object too large
当然,任何索引范围为 1..Integer'Last 的数组都可以引发 Storage_Error。编译器警告您这种可能性。尝试限制数组类型的索引范围,例如:
subtype Indices is Integer range 0..1024;
type Vector is Array (Indices range <>) of Integer;
type Array_Ending_At (Max : Indices := 0) is
record
Mat : Vector(1..Max);
end record;
当使用默认判别式声明变量时,以后可以通过赋值更改判别式。这意味着编译器(至少 GNAT 这样做)将分配(在堆栈上)足够的空间来容纳具有最大允许值(在这种情况下为 Integer'Last)的任何判别式的对象。
要么增加筹码量(不一定推荐),要么使用更适合您问题的不同子类型:
subtype Foo is Integer range 1..10;
type Vector is array (Foo range <>) of Integer;
如您所见,这是一个编译器问题。 Janus/Ada 编译器会毫无怨言或 run-time 例外地接受您的代码。
你的变量X
是一个不受约束的对象;判别式(以及对象的大小)可以通过 full-record 赋值来改变。 ARM 对如何实现这些事情保持沉默。 GNAT 已选择分配足够的 space 以获得最大可能的价值;由于 X
是在堆栈上分配的,因此使用 GNAT 的默认堆栈大小将没有足够的 space (如果您在堆上分配它,您可能没有问题)。 Janus 只为当前值分配足够的 space,这可能导致 X.Mat
被隐式分配到堆上。
Janus 方式更 developer-friendly 并且对于大多数应用程序来说都是可以接受的,开发人员不关心东西分配在哪里,但是有些情况下隐式堆分配是不能接受的,所以 GNAT 方式是更一般。