为什么 Ada 不捕获这个指定的范围检查?
Why is Ada not trapping this specified range check?
我正在阅读 learn.adacore.com 教程并遇到了一个我不确定的问题。
具体来说,我了解到 Ada 旨在捕获试图溢出具有指定范围定义的变量的尝试。
在下面的例子中,第一次尝试这样做会导致编译器 'range check failure',这是预期的。但是下面一行并没有捕获它,我不确定为什么:
with Ada.Text_IO; use Ada.Text_IO;
procedure Custom_Floating_Types is
type T_Norm is new float range -1.0 .. 1.0;
D : T_Norm := 1.0;
begin
Put_Line("The value of D =" & T_Norm'Image(D));
-- D := D + 1.0; -- This causes a range check failure at run time = completely expected.
Put_Line("The value of D =" & T_Norm'Image(D + 1.0)); -- This doesn't?
end Custom_Floating_Types;
因为您没有在 D 中存储大于范围的值。
'图片的定义说:
For every scalar subtype S:
S'Image denotes a function with the following specification:
function S'Image(Arg : S'Base)
return String
如您所见,它采用基本(无约束)类型的参数
T_Norm'Image(D + 1.0) 既不分配也不读取超出范围的值。它要求(D + 1.0)的'图像属性(字符串表示),这与要求(1.0 + 1.0)相同。
我可以看到两种可能引起混淆的方式。首先,“属性”这个名称可能会被误解为暗示“图像涉及 D 的某些内在因素。但事实并非如此。 'Image 属性只是一个函数,因此 D 只是定义参数值的表达式的一部分(在您的示例中 = 2.0)。
其次,'Image属性来源于Float。因此,任何 Float 都可以作为它的参数。
您可以创建一个仅接受 T_Norm'范围参数的函数,并使该函数成为 T_Norm 的属性。参见 Ada 参考手册 4.10。
你有几个很好的答案,但我要添加另一个,因为很明显你希望表达式 D + 1.0
引发异常,而你的答案没有解释为什么它没有。
像
这样的类型声明
type T_Norm is new float range -1.0 .. 1.0;
大致相当于
type T_Norm'Base is new Float;
subtype T_Norm is T_Norm'Base range -1.0 .. 1.0;
类型(称为“基本类型”)没有给出名称,但通常可以使用 'Base
属性引用它。给定的名称是一个子类型,称为“第一个命名的子类型”。
这个区别很重要,但往往没有得到足够的重视。正如 egilhh 所解释的,T_Norm'Image
是根据 T_Norm'Base
定义的。算术运算符也是如此。例如,"+"
定义为
function "+" (Left : in T_Norm'Base; Right : in T_Norm'Base) return T_Norm'Base;
2.0 显然在 T_Norm'Base
的范围内,因此评估 D + 1.0
没有违反任何约束,也没有将其传递给 T_Norm'Image
。但是,当您尝试将结果值分配给具有子类型 T_Norm
的 D
时,会检查该值是否在子类型的范围内,并且会引发异常,因为检查失败.
在其他地方使用这种区分是为了使语言合理地工作。比如约束数组类型
type A is array (1 .. 10) of C;
大致相当于
type A'Base is array (Integer range <>) of C;
subtype A is A'Base (1 .. 10);
如果你这样做
V : A;
... V (2 .. 4)
您可能会遇到问题,因为切片没有 A
的边界。但它有效,因为切片没有子类型 A
而是匿名子类型 A'Base (2 ..4)
.
我正在阅读 learn.adacore.com 教程并遇到了一个我不确定的问题。
具体来说,我了解到 Ada 旨在捕获试图溢出具有指定范围定义的变量的尝试。
在下面的例子中,第一次尝试这样做会导致编译器 'range check failure',这是预期的。但是下面一行并没有捕获它,我不确定为什么:
with Ada.Text_IO; use Ada.Text_IO;
procedure Custom_Floating_Types is
type T_Norm is new float range -1.0 .. 1.0;
D : T_Norm := 1.0;
begin
Put_Line("The value of D =" & T_Norm'Image(D));
-- D := D + 1.0; -- This causes a range check failure at run time = completely expected.
Put_Line("The value of D =" & T_Norm'Image(D + 1.0)); -- This doesn't?
end Custom_Floating_Types;
因为您没有在 D 中存储大于范围的值。
'图片的定义说:
For every scalar subtype S:
S'Image denotes a function with the following specification:
function S'Image(Arg : S'Base) return String
如您所见,它采用基本(无约束)类型的参数
T_Norm'Image(D + 1.0) 既不分配也不读取超出范围的值。它要求(D + 1.0)的'图像属性(字符串表示),这与要求(1.0 + 1.0)相同。
我可以看到两种可能引起混淆的方式。首先,“属性”这个名称可能会被误解为暗示“图像涉及 D 的某些内在因素。但事实并非如此。 'Image 属性只是一个函数,因此 D 只是定义参数值的表达式的一部分(在您的示例中 = 2.0)。
其次,'Image属性来源于Float。因此,任何 Float 都可以作为它的参数。
您可以创建一个仅接受 T_Norm'范围参数的函数,并使该函数成为 T_Norm 的属性。参见 Ada 参考手册 4.10。
你有几个很好的答案,但我要添加另一个,因为很明显你希望表达式 D + 1.0
引发异常,而你的答案没有解释为什么它没有。
像
这样的类型声明type T_Norm is new float range -1.0 .. 1.0;
大致相当于
type T_Norm'Base is new Float;
subtype T_Norm is T_Norm'Base range -1.0 .. 1.0;
类型(称为“基本类型”)没有给出名称,但通常可以使用 'Base
属性引用它。给定的名称是一个子类型,称为“第一个命名的子类型”。
这个区别很重要,但往往没有得到足够的重视。正如 egilhh 所解释的,T_Norm'Image
是根据 T_Norm'Base
定义的。算术运算符也是如此。例如,"+"
定义为
function "+" (Left : in T_Norm'Base; Right : in T_Norm'Base) return T_Norm'Base;
2.0 显然在 T_Norm'Base
的范围内,因此评估 D + 1.0
没有违反任何约束,也没有将其传递给 T_Norm'Image
。但是,当您尝试将结果值分配给具有子类型 T_Norm
的 D
时,会检查该值是否在子类型的范围内,并且会引发异常,因为检查失败.
在其他地方使用这种区分是为了使语言合理地工作。比如约束数组类型
type A is array (1 .. 10) of C;
大致相当于
type A'Base is array (Integer range <>) of C;
subtype A is A'Base (1 .. 10);
如果你这样做
V : A;
... V (2 .. 4)
您可能会遇到问题,因为切片没有 A
的边界。但它有效,因为切片没有子类型 A
而是匿名子类型 A'Base (2 ..4)
.