Ada 中越界值的显式转换

Explicit conversion of out-of-bounds value in Ada

假设我声明了一些类型

type ABC_TYPE is range 0 .. 7; subtype AB_SUBTYPE is ABC_TYPE range 0 .. 3; type DE_TYPE is range 1 .. 4;

以下的预期行为是什么:

abc : ABC_TYPE := 7; ab : AB_SUBTYPE := AB_SUBTYPE(abc); de : DE_TYPE := DE_TYPE(abc);

编译时没有范围检查?

正如所写,您的代码包含可以在编译时轻松检测到的约束违规。 pragma Suppress (All_Checks) 允许编译器抑制 runtime 检查(ARM 11.5(2)),但 GNAT 借此机会说

notalex.adb:11:23: warning: value not in range of type "AB_Subtype" defined at line 7
notalex.adb:11:23: warning: "Constraint_Error" will be raised at run time
notalex.adb:12:20: warning: value not in range of type "DE_Type" defined at line 8
notalex.adb:12:20: warning: "Constraint_Error" will be raised at run time

然后

$ ./notalex 

raised CONSTRAINT_ERROR : notalex.adb:11 range check failed

但是,如果像这里一样让编译时的检查变得稍微困难​​一些,

with Ada.Text_IO; use Ada.Text_IO;
procedure Notalex is

   pragma Suppress (All_Checks);

   type ABC_Type is range 0 .. 7;
   subtype AB_Subtype is ABC_Type range 0 .. 3;
   type DE_Type is range 1 .. 4;

   abc : ABC_Type;
   ab : AB_Subtype;
   de : DE_Type;

   procedure Check (Value : ABC_Type) is
   begin
      abc := Value;
      ab := AB_Subtype (abc);
      de := DE_Type (abc);
   end Check;

begin
   Check (7);
   Put_Line ("abc: " & ABC_Type'Image (abc));
   Put_Line ("ab: " & AB_Subtype'Image (ab));
   Put_Line ("de: " & DE_Type'Image (de));
end Notalex;

运行时检查被禁止。使用 GNAT(在 Mac OS X 上),输出为

$ ./notalex 
abc:  7
ab:  7
de:  7

对此有两点要说:第一,您的程序现在正在其设计范围之外执行,后果可能是灾难性的;其次,幸运的是 GNAT 的 ABC_Type’Image 和朋友们在面对超出范围的输入时也没有失败。

没有范围检查它不是 Ada,所以结果是未定义的。您可以尝试使用不同的编译器,看看它们做了什么,但如果其中一些编译器做同样的事情,那是(至少在技术上)一个幸运的巧合。

正如 Jacob 所说,结果不是由语言定义的。最可能的行为是,编译器将生成代码,将这些值视为具有特定 "natural" 范围的整数,并且只要它们适合该范围,就会简单地复制整数。

在你的例子中:

type ABC_TYPE is range 0 .. 7;
subtype AB_SUBTYPE is ABC_TYPE range 0 .. 3;
type DE_TYPE is range 1 .. 4;

abc : ABC_TYPE := 7;
ab : AB_SUBTYPE := AB_SUBTYPE(abc);
de : DE_TYPE := DE_TYPE(abc);

在最常用的处理器上,编译器会将变量存储为 1、2 或 4 字节整数。 1 字节整数的范围将是 0..255 或 -128..127——对于这种情况,这并不重要。因此,将发生的情况是 7 将存储在分配给 de 的 1、2 或 4 字节整数中。然后,当程序访问 de 时,它很可能只会读取该整数并使用它。我希望 DE_TYPE'Image(de) 可以正常工作,因为可能有一些低级函数将 "integer" 转换为图像,它接受任何 32 位(或 64 位)整数作为一个参数。 请注意,我不建议您依赖这种行为。 鉴于我对编译器生成代码的了解,这正是我认为最有可能发生的情况。另请注意,尽管 ab 可以存储为 2 位整数,但编译器不太可能这样做(打包记录或打包数组除外),因为它不是处理器可以处理的自然整数大小。

不过在这种情况下:

type ABC_TYPE is range 0 .. 10000;
subtype ABC_SUBTYPE is ABC_TYPE range 0 .. 100;

abc : ABC_TYPE := 1234;
ab : AB_SUBTYPE := AB_SUBTYPE(abc);

现在,如果禁止范围检查,编译器可能会在将 abc 分配给 ab 之前将其截断为一个字节。这将通过砍掉高位字节,留下 210 来实现,这意味着 abc 将具有值 210 或 -46,具体取决于该字节是否被视为有符号。 (它仍然超出 AB_SUBTYPE 的范围,但由于范围检查被禁止,因此不会导致异常。)不同的编译器在这种情况下可能有不同的行为。