跳转到内容

Ada 编程/基础

来自维基教科书,为开放世界提供开放书籍

Ada. Time-tested, safe and secure.
Ada. 经久耐用、安全可靠。

"Hello, world!" 程序

[编辑 | 编辑源代码]

"Hello, world!"

[编辑 | 编辑源代码]

语言的 语法 的一个常见示例是 Hello world 程序。这是一个简单的 Ada 实现

文件:hello_world_1.adb,Crate:basic (查看, 纯文本, 使用 Alire 下载, Alire 包信息)
with Ada.Text_IO;

procedure Hello is
begin
   Ada.Text_IO.Put_Line("Hello, world!");
end Hello;

with 语句将包 Ada.Text_IO 添加到程序中。此包包含在每个 Ada 编译器中,并包含文本输入/输出所需的所有功能。with 语句使 Ada.Text_IO 的声明可供过程 Hello 使用。这包括在 Ada.Text_IO 中声明的类型、Ada.Text_IO 的子程序以及 Ada.Text_IO 中为公开使用而声明的所有其他内容。在 Ada 中,包可以用作工具箱。Text_IO 为在一个易于访问的模块中进行文本输入和输出提供了一组工具。以下是包 Ada.Text_IO 的部分概述

package Ada.Text_IO is

   type File_Type is limited private;

   --  more stuff

   procedure Open(File : in out File_Type;
                  Mode : File_Mode;
                  Name : String;
                  Form : String := "");

   --  more stuff

   procedure Put_Line (Item : String);

   --  more stuff

end Ada.Text_IO;

接下来在程序中我们声明一个主过程。Ada 主过程不需要被命名为 "main"。任何简单的名称都可以,这里就是 Hello。编译器可能允许将过程或函数用作主子程序。 [1]

Ada.Text_IO.Put_Line 的调用将文本 "Hello World" 写入当前输出文件。

with 子句使包的内容 通过选择可见:我们需要用其完整包名 Ada.Text_IOText_IO 包中的过程名 Put_Line 添加前缀。如果你需要更频繁地使用包中的过程,则需要某种捷径。有两个选择

"Hello, world!" 带重命名

[编辑 | 编辑源代码]

通过重命名包,可以为任何包名提供一个更短的别名。[2] 这减少了打字量,同时保留了一些可读性。

文件:hello_world_2.adb,Crate:basic (查看, 纯文本, 使用 Alire 下载, Alire 包信息)
with Ada.Text_IO;

procedure Hello is
   package IO renames Ada.Text_IO;
begin
   IO.Put_Line("Hello, world!");
   IO.New_Line;
   IO.Put_Line("I am an Ada program with package rename.");
end Hello;

"Hello, world!" 带本地使用

[编辑 | 编辑源代码]

Theuse 子句使包的所有内容对声明它的作用域直接可见。use 可以放在本地或全局(见下文)。与重命名一样,这减少了打字量,同时保留了一些可读性。

文件:hello_world_3.adb,Crate:basic (查看, 纯文本, 使用 Alire 下载, Alire 包信息)
with Ada.Text_IO;

procedure Hello is
   use Ada.Text_IO;   
begin
   Put_Line("Hello, world!");
   New_Line;
   Put_Line("I am an Ada program with package use.");
end Hello;

use 可以用于包,并以以下形式使用use type 用于类型。use type 仅使给定类型的 运算符 直接可见,但不包括类型上的任何其他操作。

"Hello, world!" 带全局使用

[编辑 | 编辑源代码]

使用use 子句在任何作用域之外都会使包的所有内容对整个编译单元直接可见。它允许更少的打字,但会降低可读性,并可能导致名称冲突。

文件:hello_world_4.adb,Crate:basic (查看, 纯文本, 使用 Alire 下载, Alire 包信息)
with Ada.Text_IO;
use Ada.Text_IO;

procedure Hello is    
begin
   Put_Line("Hello, world!");
   New_Line;
   Put_Line("I am an Ada program with package use.");
end Hello;

有了这么多选择,需要考虑在什么情况下使用哪个选择。一个建议的“经验法则”

  • 全局use 用于最常用的包(s)
  • renames 用于大多数其他包(s)
  • 本地use 用于仅在一个过程中使用的包
  • 不使用userenames 用于仅使用一次的包(s)

你可能还有更简单的规则(例如,始终useAda 及其子包,永不use 任何其他内容)。

Ada 开发早期另一个规则是全局use 用于所有包,除非发生名称冲突。

编译 "Hello, world!" 程序

[编辑 | 编辑源代码]

有关如何在各种编译器上构建“Hello, world!”程序的信息,请参阅构建章节。

常见问题解答:为什么“Hello, world!”如此之大?

[编辑 | 编辑源代码]

Ada 初学者经常会问,像“Hello, world!”这样简单的程序怎么会产生这么大的可执行文件。原因与 Ada 无关,通常可以在使用的编译器和链接器选项中找到 - 或者更确切地说,是未使用的选项。

Ada 编译器 - 或者一般来说好的编译器 - 的标准行为不是创建最佳代码,而是为了易用性而优化。这样做是为了确保一个“开箱即用”的系统,从而不会因不必要的复杂性而吓跑潜在的新用户。

您可以在下载示例程序的同时下载的 GNAT 项目文件,使用更优化的编译器、绑定器和链接器选项。如果您使用这些选项,“Hello, world!”将变得小很多。

 32K ./Linux-i686-Debug/hello_world_1
8.0K ./Linux-i686-Release/hello_world_1
 36K ./Linux-x86_64-Debug/hello_world_1
 12K ./Linux-x86_64-Release/hello_world_1
1.1M ./Windows_NT-i686-Debug/hello_world_1.exe
 16K ./Windows_NT-i686-Release/hello_world_1.exe
 32K ./VMS-AXP-Debug/hello_world_1.exe
 12K ./VMS-AXP-Release/hello_world_1.exe

为了比较,一个简单的 gnat make 编译的大小

497K hello_world_1 (Linux i686)
500K hello_world_1 (Linux x86_64)
1.5M hello_world_1.exe (Windows_NT i686)
589K hello_world_1.exe (VMS AXP)

值得一提的是,使用 GNAT/MSVC 7.1/GCC(C) 编译的 hello_world(Ada、C、C++)在给定可比的优化和链接器方法的情况下,都产生大小大致相同的可执行文件。

需要注意的事项

[编辑 | 编辑源代码]

准备好识别 Ada 的一些重要特性,这些特性对于学习其语法和语义至关重要,将会有所帮助。

梳状格式

[编辑 | 编辑源代码]

在所有控制结构和模块结构中都存在一种梳状格式。请参阅以下示例以了解梳状格式。您不必理解这些示例的作用 - 只需查找布局中的相似之处即可。

if Boolean expression then
   statements
elsif Boolean expression then
   statements
else
   statements
end if;
while Boolean expression loop
   statements
end loop;
for variable in range loop
   statements
end loop;
declare
   declarations
begin
   statements
exception
   handlers
end;
procedure P (parameters : in out type) is
   declarations
begin
   statements
exception
   handlers
end P;
function F (parameters : in type) return type is
   declarations
begin
   statements
exception
   handlers
end F;
package P is
   declarations
private
   declarations
end P;
generic
   declarations
package P is
   declarations
private
   declarations
end P;
generic
   declarations
procedure P (parameters : in out type);

请注意,分号始终用于终止语句和声明;空行(或单独的分号)不是有效的语句:空语句是

null;

类型和子类型

[编辑 | 编辑源代码]

类型子类型之间存在重要的区别:类型由一组值及其操作给出。子类型由类型和一个约束给出,该约束限制了值集。值始终属于一种类型。对象(常量和变量)属于子类型。这概括、澄清并系统化了一种关系,例如Integer 和 1..100 之间的关系,这种关系在Pascal 的语义中是特殊处理的。

约束类型和无约束类型

[编辑 | 编辑源代码]

约束类型和无约束类型之间存在重要的区别。无约束类型具有一种或多种自由参数,这些参数会影响其大小或形状。约束类型固定了这些参数的值,因此确定了其大小和形状。简单来说,对象必须属于约束类型,但形式参数可以是无约束类型(它们采用任何相应实际参数的约束)。这解决了 Pascal 中数组参数的问题(以及其他问题)。

动态类型

[编辑 | 编辑源代码]

PascalC 中的值必须是静态的(例如,数组的下标边界),但在 Ada 中它们可以是动态的。但是,在动态求值无法允许合理实现的某些情况下(例如,在设置浮点类型的精度位数时),需要静态表达式。

关注点分离

[编辑 | 编辑源代码]

Ada 一直支持接口和机制的分离。您可以在的格式中看到这一点,它将包的声明与其主体分开;以及在私有类型的概念中,其在 Ada 数据结构方面的表示在包含其定义的作用域之外是不可访问的。

在哪里寻求帮助

[编辑 | 编辑源代码]

大多数 Ada 专家潜伏在Usenet 新闻组 comp.lang.ada(英语)和fr.comp.lang.ada(法语)中;可以使用新闻阅读器或通过众多网络接口中的一个来访问它们。这是所有与 Ada 相关问题的地方。

这些新闻组中的人愿意提供帮助,但不会为学生完成作业;他们不会发布作业的完整答案。相反,他们会为学生提供指导,让他们自己找到答案。

有关更多在线资源,请参阅本维基教科书介绍中的外部链接部分。

  1. 主子程序甚至可以有参数;哪些子程序可以用作主子程序是实现定义的。参考手册在10.2: LRM 10.2(29) [注释]中解释了详细信息:“……,实现需要支持所有作为公共无参数库过程的主子程序。” 表示未嵌套在另一个子程序中,例如,以及现在我们不必关心的其他事情。
  2. renames 也可以用于过程、函数、变量、数组元素。它不能用于类型 - 类型重命名可以使用subtype 完成。
华夏公益教科书