皮亚杰“A、B错误”:A和B必须浮点标量问题,怎么解决

扫一扫体验手机阅读
Ada 程序设计语言(The Ada Programming Language)[第一集]
&&& 《Ada 程序设计语言》的版权隶属于网站 ,允许任何用户翻阅、传播、批评等等,只要读者想的出的行为,都可以作用于本教材。唯一一条禁令则是:不允许恶劣地直接抄录本教材,并冠以他人名字为作者(这种人肯定不得好死)。版权宣言结束。&
&&& 经过几个星期的努力,《Ada 语言程序设计》终于有了基本框架,为了及早听取读者的意见和促进 Ada 的推广,在未最终完稿前,笔者将它搬上了
&&& 在此,我想提一下写作动机。大约是在去年,我才始接触 Ada 语言,当时可以说“一见钟情”,心情激动的很,当场被 Ada 所吸引。按照惯例,是需要在网络上找点 Ada 的资料,但不幸的是,国内好像对此很冷淡,没有什么网站,当时只找到一个在 163.com 上的 ~wangcity 个人主页,但没有多少资料,而且现在都已经关闭了。当时就有想法,自己也办一个 Ada 网站,促进 Ada 在国内的推广,可惜自己功力太浅(现在也不怎么样),而且当时感觉自己过于才疏学浅,将大力花在了英语、社会科学上,于是《经济学》、《曾国藩家书》、《剑桥中国史》等书的地位就相当高,而自己又是倒霉透顶的重点中学学生,时间上也很不够。直至今年初,越来越感觉国内学术风气之糟糕,一味跟着当前市场需求走,不管长远利益;在清华图书馆检索时,发现 Ada 的书都是以前的古董了,至此才决定硬着头皮写一份中文教材。由于自己也没有什么经验可言,一路上是摸着路边的石头过河,也屡次想放弃,幸运的是,大致的框架是在今天完成了。接下来的工作,大概就是扩充已知的未添加的内容,同时听取读者反馈,对原有内容做做修改。
&&& 由于自己才不过是高二学生而已,水平、经验方面都很不足,因此希望读到本教材的朋友能多提意见,多抓错误(可不是什么客套话,的确很需要别人的意见),在此就先谢过了。同时也希望能有志于推广 Ada 在中国的使用的朋友能与我一起交个朋友,否则一个人孤单单的实在乏味。
*本教材适宜对 C、C++ 或其它语言以及操作系统有所了解的读者。
*在内容分布上,第1章-第13章主要集中在语法部份,第14章以后的内容主要集中在预定义程序包上,基于 Ada Reference Manual,读者可自行跳过一些章节,无须按部就班或直接参看 RM。
第13章 Interface to Other Languages(请问中文怎么说好)
第15章 输入输出
第16章 数值处理
第17章 命令行环境
1.1概述(Overview)
&&& Ada 语言最初设计是为了构建长周期的、高度可靠的软件系统。它提供了一系列功能来定义相关的数据类型(type)、对象(object)和操作(operation)的程序包(package)。程序包可以被参数化,数据类型可以被扩展以支持可重用库的构建。操作既可以使用方便的顺序控制结构,通过子程序(subprogram)来实现,也可以通过包含并发线程同步控制的入口(entry)来实现。Ada 也支持单独编译(separate compilation),在物理层上支持模块性。
&&& Ada 包含了很复杂的功能以支持实时(real-time),并发程序设计(concurrent programming)。错误可以作为异常(exception)来标示,并可以被明确地处理。Ada 也覆盖了系统编程(system programming);这需要对数据表示和系统特性访问的精确控制。最后,提供了预定义的标准程序包,包括输入输出、字符串处理、数值计算的基本函数和随机数生成。
——译自《Ada Reference Manual》Section1:General
&&& 在本章里,我们将会初步介绍一下 Ada,以给读者留下大致的印象。
1.2 Ada 的历史(The History of Ada)
&&& 为了更好的理解 Ada,它的历史有必要简要地了解一下。
&&& 1974 年时,美国国防部(DoD)意识到开发和维护嵌入式系统(固化在硬件中的系统,如导弹弹导系统)耗费了过多的时间,精力和资金。 
&&& 当时,在使用的计算机语言有 450 多种,这增加了开发新系统以及培训程序员使熟悉现有系统的时间和成本。维护工作也由于没有标准化的工具(编辑器,编译器等)而受阻。所有这些因素使 DoD 意识到它需要一门强大的语言,能被所有嵌入式电脑供应商使用。
&&& 开发工作始于 1975 年,当时 DoD 列举了一系列的语言需求;但没有一门现有语言指定了这些特性,因此在 1977 年,DoD 起草了一份建议,开发一门新的语言。不像COBOL 这些语言由专门的委员会制定,新语言是一场竞争的主题,在产业界和学术界的评估中产生。
&&& 在众多竞争者当中,有 4 家被选中以完成进一步的工作。最终只剩下 Cii-Honeywell Bull 公司。这门语言被命名为 Ada。设计小组由 Jean Ichbiah 领导,对语言全权负责。
  在 1983,Ada 成为了一个 ANSI 标准 ANSI/MIL-STD-1815A。此年成为一个 ISO 标准。在参考手册中定义的语言通常称为 LRM 或 ARM(Ada Reference Manual)。在 Ada 的相关书籍和编译器的报错信息中经常出现手册内容的引用。对于任何 Ada 站点,参考手册都是推荐的;虽然很难阅读,但它是所有 Ada 问题的最权威解释(一个小组正在澄清语言定义中已发现的语义不清的内容)。
&&& Ada 也经过了一次修正,即 1995 的新的 ISO 标准。新标准修正了 Ada83 的很多缺陷,并进一步扩展了它的功能(在修正工作中,有个临时的标准,即 Ada9x,不少 Ada 文章是在 这段时间写的,因此有些内容在细节上可能与 Ada95 有所区别,但主要原理差不多)。
&&& 为了防止 Ada 编译器的不兼容版本的扩散,Ada Joint Program Office (控制 Ada 语言的执行部门,于 1998 年 10 月 1 日关闭,见 ) 采取了不寻常的做法 - 他们注册 Ada 商标。除非通过他们的兼容性测试,编译器厂商不允许出售 'Ada' 编译器。这在不久以后放松了,保护协议变成了 `Validated Ada'。因而产生的 Ada 确认证书被限制在一定的时间内并有一个期满时间。当时间过期后,该编译器不能再被标记为`Validated Ada' 编译器。通过这种方式,AJPO 确保当前市场上的编译器与当前标准相一致。
&&& 目标是使所有的 Ada 程序能在所有系统上被编译-在这点上,AJPO 比其它语言小组做得好。
上述内容基本上是从 Quick Ada 翻译过来的(以前翻译该教材“半途而废”的残留品,直接引用一下了),Ada 语言的详细历史细节见。
1.3 与 C 和 C++ 的比较(Contrast:Ada and C,C++)
&&& 由于 Ada 出生年月迟了一点,而且目前的操作系统基本上由 C,C++ 写成,导致 Ada 在“平民层”的推广比较糟糕,至今还不是很流行, 一文对此有比较详细的解释。而 Ada 爱好者们为了显示 Ada 的优越性(这种心情相当能理解),将 Ada 与 C,C++ 做了一系列比较,其结果反正综和指数都是 Ada 高,这方面文章有不少,如 ,。在这里,我们只初略地了解一下 Ada 的优势即可,在读者朋友接下去的学习中,应该是能从心里感受到 Ada 的优点。
更高的安全性、可靠性。Ada 中对于访问内存、数值计算等很多方面有一些严格的规定,而没有 C 和 C++ 那么自由;程序的错误绝大部份能在编译和运行时检测到,以至于可以不需要编译器,另外,语言也包含异常特性,能方便地处理错误。
更高的移植性。在 Unix 和 Windows 下有 C 编程经验的朋友应该对于兼容性深有体会,很多代码纯粹是为了适应不同的系统增添的,对于实际工作没多大用处。但 Ada 的初始语言环境中就有了异常(约等于 Unix 下的 Signal)、任务(线程)、分布式计算、随机数产生、宽字符集很多特性的支持,而在现在的具体操作系统中,这些特性往往随系统而异。即使 Ada95 里缺少一些功能,也可以通过额外标准和函数库来弥补:GDI 库,可以用 GtkAda,在 Windows 和 X 下通用;Ada 也有一个 Posix 接口的标准,可以使用函数库 Florist 来调用 Posix 的函数…… 用户层是大大省力---只要自己的操作系统上有所需的编译器和函数库即可。
语法明确,基本上没有令人混淆的地方。Ada 程序的源代码远远比 C 或 C++ 的代码易懂。看程序的人是减轻了不少脑负担。
&&& 总之,C 和 C++ 能做的 Ada 肯定能做,但&Ada 要省时方便的多。读者在学习 Ada之后,无需多说也就明白了,笔者在初学 Ada 时就有耳目一新的感觉,唯一的遗憾是 Ada 不流行。
1.4 网络资源(Internet Resources)
&&& Ada 虽然在国内不流行,但在国外还是有不少网站,下面是只列举一小部份,至于更多的资源,读者可至 查找:
,由 Magnus Kempe 维护,里面包含了不少 Ada 相关的文档、软件
Public Ada Library (PAL)。PAL 是 Ada 软件、文档的图书馆。主站点在, 以及法国的一个映像站点,PAL 目前由
,由 AJPO 发起的一个站点,也包含了不少相关信息 。
,是 ACM 的一个。
,很不错的一个站点,有相关教材、文档、Faq、Linux 等链接。
,Gnat,Glade 等软件的老家。
,不用多介绍了。
1.5 第一个程序(The First Program)
&&& 为了了解 Ada 程序的大致结构,举一个例子是难免的。大部份书籍一般都是用"hello world"程序来开始,我们下面就见识一个在终端屏幕上输出 "Hello World!"的简例。000 -- filename:hello.adb;
001 with Ada.Text_IO;
002 procedure Hello is
Ada.Text_IO.Put ("Hello World!");
Ada.Text_IO.New_L
&&& 先介绍一下在本教材中代码的一些问题:每行代码前的 000,001 等数字表示该代码是第几行,只为了讲解方便,在实际源代码中是不存在的;with,procedure 等保留字(reserved word)都用粗体表示,以示区别;有些字是用斜体表示,表示该字是用其它有效字符替换。
&&& 现在让我们分析上述的简单程序:
[000]标示该程序文件名为 hello.adb,在程序中并不需要;-- 是注释符,表示从其所在位置至行尾都是注释,对程序没有什么影响,与 C 的 /*& */类似。
[001] Ada.Text_IO 是预定义的一个程序包(package);with package_name和 C 的 include 功能差不多。[002]-[006]是程序的主体部份。与 C 下的 main 函数类似,Ada 也需要一个主过程(main procedure),在这个例子中是过程 Hello。过程的用法和上例一样,都是
procedure procedure_name is
statements1;
statements2;
end procedure_
&&& statement1 可以是变量、常量、函数、过程等的声明;statements2 是过程 procedure_name 要执行的语句,对象的声明不能在这部份;end 后的 procedure_name 不是必需的,但为了程序的可读性,应加上。
[003],[004] 分别输出"Hello World!" 和新行符。Put 和 New_Line 都是 Ada.Text_IO 里的过程。
&&& 但上7例调用过程 Put 和 New_Line 的方法比较罗嗦,因此我们也可以使用 use 语句:
000 -- filename:hello.adb;001 with Ada.Text_IO; use Ada.Text_IO;&&&002 procedure Hello is003 begin004&&& Put ("Hello World!");005&&& New_L006 end H& &
&&& 这样 Ada 编译器就能在程序包 Ada.Text_IO 中自动搜寻 Put,New_Line,而无需用户指定它们所在的准确位置。
&&& 我们在将上例略微改动以下,以使读者了解一下声明部份:000 -- filename:hello.adb
001 with Ada.Text_IO; use Ada.Text_IO;
002 procedure Hello is
Str:String := "Hello World!";
&&& 在 is 和 begin 之间,声明了一个字符串变量 Str,它的初始值为"Hello World"。String 是预定义的字符串类型。上述的声明方式和 Pascal 差不多。
&&& 现在我们对 Ada 程序长的什么样已有了基本的认识,下面需要了解几个术语。一个 Ada 程序是由一个或多个程序单元组成(program unit)。一个程序单元可以为:
子程序(subprogram),定义一些可执行运算。过程(procedure)和函数(function)都是子程序。
程序包(package),定义一些实体(entity)。程序包是 Ada 中的主要分组机制,类似于 C 的函数库,Modula 的"module"。
任务单元(task unit),与线程类似,定义一些计算,然后并发执行。
保护单元(protected unit),在并发计算中协调数据共享,这在 Ada 83 中不存在。
类属单元(generic unit),帮助构建可重用组建,和 C++ 的模板类似。
&&& 后3类属于高级话题,在后面的章节中我们会依次介绍。程序单元又可为两部份:
声明部份(declaration)。定义对其它程序的接口,有些可用资源可以被用户使用,与 C 下的'.h'文件相似。
主体部份(body)。是声明部份的具体实现,等价与 C 的'.c'文件。
&&& 其中程序包(package)和子程序(subprogram)是用的最广泛的2个程序单元。大部份 Ada 程序基于一堆程序包,在以一个主过程(main proceudre) 来开始 Ada 程序&。
第2章 基本数据类型和表达式(Basic Types and Expressions)
2.1 概述(Overview)
&&& 数据类型是一门计算机语言最基本的特性,表示一个对象的类型,是数字、字符或其它类型。由于 Ada 在数据类型上提供的强大处理能力,我们又不能很简单地认为数据类型仅是定义一个对象的类型。在 Ada 里,数据类型可以自己创建,它的相关运算符也可以自己定义,同时又有数据类型属性这项特性,具有相当大的灵活性。学过其它的语言,特别是有 C 和 Pascal 背景的朋友初次接触时可能会感到有点新鲜。
&&& 创建新类型,是用户自己定义数据类型,包括该类型的名称、取值范围及相关操作;其中又包括了派生类型和创建子类型,即以现有数据类型为母类型创建新类型,继承母类型的一部份属性。
&&& 数据类型属性,如同我们玩RPG游戏时的人物属性:体力值、魔法值一样,是说明该类型固有的属性,包括最小取值范围、最大取值范围等等。
&&& 本章将会先介绍词法元素以及创建数据类型的基础性知识,然后是整型(integer)、实型(real)、字符型(character)、布尔型(boolean)、枚举类型(enumuration)这几种标量类型,最后则是相关的数据类型属性、类型限制和类型转换、表达式和运算符。
2.2 词法元素(Lexical Element)
&&& Ada 里的词法元素与其它语言的定义还是有不小差别,下面按照 RM95 关于词法元素的分类来逐项介绍,包括标识符、保留字、字符、数值文字等及它们的一些规则。
2.2.1 基本字符集(Character Set)
&&& Ada 95 规定的标准字符集是 Latin-1,支持8位(基于ISO-8869)和16位(基于ISO-10646)字符,在非标准模式下也可用本地字符集,具体情况取决于当前的系统。(一般来说,涉及字符时默认是指 Latin-1,程序几乎都是用 Latin-1 字符集写的)
&&& 字符在RM 95 中是分成了三类:图形字符(graphic character)、格式控制符(format effector)、其它控制符(other control function),它们所表示的范围为:
&&& 图形字符包括字母(letter)、数字(digit)、空格符(space)、特殊字符(special character)(例如" # & ' ( ) * + , - . / : ; & = & _ | { } [ ]);
&&& 格式控制符包括水平制表符(HT)、垂直制表符(VT)、回车(CR)、换行(LF)、换页(FF);
&&& 其它控制符则是除了格式控制符以外的控制符。
&&& 更详细的内容参见RM 95、ISO 8869,ISO 10646。
&&& Ada 是大小写忽略的(除了字符和字符串中的实际内容,如字符'z'和'Z'不相同,但标识符 z 和 Z 相同),但为了可读性,一般来说变量名或函数名首字母都会大写,其余小写,缩近格式也需要引起注意。根据实际情况尽量保证可读性。
&&& 为了兼容性,Ada95 要求编译器最少支持一行字符串和一个词法元素的长度为 200个字符(不包括行尾符)。
&&& Ada 在字符集上并没有很严格要求编译器一定要怎样,但应该支持标准字符集。
2.2.2 标识符(Identifier)
&&& Ada 中不管是变量、函数还是其它对象都需要一个名称,这就叫做标识符。如 X、Count 、me就是简单的标识符。
&&& Ada 中的标识符有以下一些注意点:
标识符一定要是字母开头,接下去可以是数字和下划线,结尾不能为下划线。如Fig_、_Lik、1me是不合法的。
两个连续的下划线不能在一起,因为有些打印机可能会将两个下划线当作一个处理。
虽然单个字符可作为标识符,但一般情况下不应该滥用这项特性(我不知道这除了少敲几个字外,还有什么意义,想想数字 0 和字母 O、数字 1 和字母l吧,绝对害死人的做法)。
不能将保留字作为标识符。在 Ada 83 中,标识符包括了保留字,但在Ada 95 中保留字从标识符中分离了出来。
.如上节所提及的,标识符是不分大小写的,但为了可读性,请注意你对标识符的命名。
2.2.3 保留字(Reserved Word)
&&& 保留字在程序语法中有特殊的含义,不属于标识符范围,这与C 和 Pascal 等语言的定义有所不同。Ada 95 中的保留字如下:abort abs abstract accept access aliased all and array at begin body
case constant declare delay delta digits do else elsif end entry exception exit
for function generic goto if in is limited loop mod new not null of or others out
package pragma private procedure protected raise range record rem renames requeue
return reverse select separate subtype tagged task terminate then type
until use when while with xor
&&& 在以后的内容中,我们会逐个解释它们的含义及作用。Ada95 的保留字比原先添加了6个:abstract, aliased, protected, requeue, tagged 和 until,虽然这可能会牵连到兼容性问题,但通常也无须计较这点。2.2.4 分隔符(Separator and Delimiter)
&&& Ada 程序中,各元素之间需要空格符、格式控制符或 EOF 隔开。RM 95里将它们作为separator,而delimiter 则是指下列特殊字符(中文有点说不清楚):& ' ( ) * + , -. / : " & = & | 或是复合型的: =& .. ** := /= &= &= && && &&。当分隔符作为注释、字符串、字符、数值的一部分时,就不再是分隔符了。
2.2.5 数值文字(Numeric Literal)
&&& 数值文字就是指数字。Ada 和 Pascal 相同,将数字分为实数型(real literal)和整数型(integer literal)两大类。实数型是有小数点的数字,整数型则无小数点。如 1.,7.0是实数型,而-882,5441,1是整数型。Ada 在数字表示上有一个很好的特性就是可以明确指定使用何种基数(2进制到16进制)表示,下面是数字的表示:十进制数(Decimal Literal)
&&& 不管是实型还是整型数,都可以在其间加上下划线,使长数字更加易读。如25615,可写为56_886_515_645_125_615或5_12_5615,下划线并不改变数字的值。但两个下划线不能是连续的,下划线也不可以在数字首部和尾部,如676__66和67_E4都是非法的。
&&& 字母 E 作为数字的指数,同时适用于实型和整型。如 123_98E4、5.087E-5、 4.8E7都是合法的,但负指数不能用于整型,指数也一定要是整数。E 大小写皆可以。基型数字(Based Literal)
&&& 在大部分语言中,都使用 10 进制数字表示;Ada 里整数可以不用10进制的表示方法书写,而是直接使用 2至16进制的表示法,格式为:Base # Number #,Base 表示所采用的进制,Number 为该进制下所表示的数字。
2##,表示2进制数 ,中间的下划线可取消,其10进值为153;
10#153#,表示10进制数153,等价与153;
16#90#,表示16进制数90,其10进值为144;
2.2.6 字符文字(Character Literal)
&&& 字符文字的表示是单个图形字符在单引号 ‘ ’中,如' a'表示小写字母a, 'K'表示大写字母K,' ' '表示一个单引号,' '表示一个空格。2.2.7 字符串文字(String Literal)
&&& 字符串是双引号(" ")之间的有序图形字符。如" What I said."就是一个字符串。表示空字符串时直接用" "。如果字符串中有双引号,一个双引号要用两个"来表示。如" He said,"" I am hungry."" ",而" He said," "I am hungry. "或" He said," I am hungry." "是不合法的。至于其它字符,如$ %之类可以直接出现在两个双引号间。与 C 语言不同,Ada 里没有与之相同的转义字符,并且EOL不会算到字符串中。
2.2.8 注释(Comment)
&&& 注释由两个连字号(hyphen)(--)开始,直到行尾。可以出现在程序的任一个地方,不影响程序本身。例如:
2.2.9 Pragmas
&&& Pragma 是编译指示(compile directive),给编译器指令如优化程序,列表控制等。它的作用往往不只影响一个编译单元,而是整个程序。
&& Pragma 是些预先定义的指令,如 pragma Page,pragma List(OFF) ,编译器也可扩展 RM 95 中 pragma。我们先接触 List,Page,Optimize 这3个 pragma。更多内容我们会在以后接触。
pragma List(identifier);pragma Ppragma Optimize(identifier);
pragma List 将 identifier On 或 Off 作为它的参数。它指定编译列表(listing of compilation) 是继续还是停止,直到在同一个编译单元内,一个pragma List 使用了相反的参数。
pragma Page 指定在 pragma 后的程序正文在新页开始(如果编译器正在列表)
pragma Optimize 有 Time,Space 或 Off 3个参数,它的影响区域直到 pragama 所在编译单元的底部。Time 和 Space 指示优化时间还是优化空间,Off则关闭优化。
  下面是简单的例子:
pragma List(Off); --关闭列表生成 pragma Optimize(Off); --关闭可选的优化
  不过,上述3个 pragma 是影响编译过程用的,基本上用户也用不着,以后涉及的 inline,Pure 等 pragma 使用频率倒挺高。
2.3 创建数据类型和子类型(Creating Types and Subtypes)
& 使用变量时,除了以某标识符作为变量的名称外,还要指定该变量的数据类型。一个数据类型定义了变量可接受的值以及所能执行的操作。比如说,一个数据类型为 Age 的变量 Bill,Age 的取值范围为 1..100,并只有 + - 这两种操作,在这里,对象(object)为名为 Bill 的变量,它的取值在 1..100 之间(包括 1,100),值的变化只能通过+ -这些基本运算符(primitive operation)来实现,而无法通过* /等其它运算符。Ada 中的数据类型,包括预定义类型,都是按照一定的格式在程序包中创建的。下面就介绍创建数据类型的一些基本内容,更多相关内容会在以后见到。2.3.1 创建新的数据类型
&&& 创建一个新类型,需要使用保留字 type,is,range。格式如下:
type type_name is range range_specifcation;
&&& type_name
&&& 例如创建上面提及的一个新类型 Age :Age is range 1 .. 100;
&&& 这样就有了一个数据类型 Age, 取值范围 1 .. 100。
&&& 有一点要注意:range_specfication 中 First 要大于 Last。 如 type months is range 12 .. 0, 实际上 months 是一个空集(null),而不是所期望的 0..12。
&&& 不同数据类型之间是不能进行混合运算的,即使取值范围和运算符一样,看以下的程序例子:
000 -- filename: putwage.adb 001 with Ada.Text_IO; use Ada.Text_IO; 002 with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; 003 procedure putwage is 004 && type Age is range 1 .. 100; 005 && type Wage is range 1 .. 100; 006&&& Bill_Age : Age := 56; 007&&& Bill_Wage: Wage := 56; 008 begin 009&&& Put ("Total wage is");010&&& Put (Bill_Wage * Bill_Age);011&&& New_L012
[001]-[002]: 使用软件包 Ada.Text_IO,Ada.Integer_Text_IO;两个软件包分别处理字符类输出和整数输出。
[003] [008] [012] 定义一个过程 putwage。
[004]-[005]: 定义新的数据类型Age,Wage,它们取值范围都为 1..100。
[006]-[007]: 声明两个变量 Bill_Age,Bill_Wage,类型分别为 Age 和Wage, 并赋予相同初始值56。
[009]-[011]:依次输出字符串"Total wage is",整数 Bill_Wage和Bill_Age的乘积,和一个新行符(EOL)。
&&& 以上程序看上去毫无问题,但根本无法编译通过。首先,没有定义类型Age和wage的 * 操作,因此Bill_Age和Bill_Wage无法相乘;第二,两者数据类型不同,即使定义了*操作,还是无法相乘。 当然也可使用后面提到的类型转换 ,如果将[010]改为Put (Integer(Bill_wage) * Integer(Bill_Age)),将会输出所要的 3136;但如果改成Put (Integer(Bill_wage * 56)),看上去也行的通,但实际结果却不是3136。不同数据之间不能进行运算,要牢牢记住。(Integer 是预先定义的一个整型,Integer(Bill_Wage)是将Bill_Wage强制转换为整型)。2.3.2 派生类型
&&& 大家可能会发现,如果像上面一样创建一个截然不同的新类型,还需要定义它的运算符,使用很不方便。因此,往往是派生现有的类型,其格式为:
typetype_name is new old_type {range range_specification};
&&& type_name
000 -- filename:putwage.adb 001 with Ada.Text_IO; use Ada.Text_IO; 002 with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; 003 procedure putwage is 004 && type Age is new Integer range 1 .. 100; 005 && type wage is new I 006&&& Bill_Age : Age := 56; 007&&& Bill_Wage: Wage := 56; 008 begin 009&&& Put ("Total wage is");010&&& Put (Bill_Wage * Bill_Age);011&&& New_L012
&&& 上例还是不能编译通过,因为派生类型只继承母类型的属性,如运算符,不同的派生类型即使母类型相同也还是属于不相同的类型。但将[10]改为Put (Integer(Bill_wage * 56))则能输出正确的结果。但是派生类型使用还是麻烦了一点,不同类型之间即使都是数字类型也无法混合使用,只是自己不用创建运算符省力了点。2.3.3 创建子类型
&&& 创建新类型和派生类型的麻烦从上文就可以感受的到,特别是在科学计算这些有很多种小类型的软件当中,上述两种方法实在过于繁杂。这时子类型(subtype)就相当有用,子类型的定义格式为:
subtypetype_name old_type {range range_specification};is
&&& type_name
000 -- putwage.adb 001 with Ada.Text_IO; use Ada.Text_IO; 002 with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; 003 procedure putwage is 004 && subtype Age is Integer range 1 .. 100; 005 && subtype Wage is I 006&&& Bill_Age : Age := 56; 007&&& Bill_Wage: Wage := 56; 008 begin 009&&& Put ("Total wage is");010&&& Put (Bill_Wage * Bill_Age);011&&& New_L012
&&& 编译通过,输出值为3136。子类型不仅继承母类型的属性,而且和母类型、其它同母类型的子类型可混合使用。
&&& 在前面的例子中的,我们都提到了取值范围,这也是 Ada 的一项“特色”:Ada 不同于 C 和 Pascal--- 赋给一个变量超过其取值范围的值或进行不合法运算,会输出错误的值而不报错,与此相反,Ada 程序在编译时会提示错误,或在运行 Ada 程序时产生Constraint_Error异常(异常和 C 中的信号Signal差不多,详见),挂起程序,来减少程序的调试时间。
2.4 标量类型(Scalar Type)
&&& 大部份语言,基本的数据类型如果按照该类型所表示的数据类型来分,一般来说可分为整型(integer),实型(real),布尔型(boolean),字符型(character)这四类,并以它们为基础构成了数组,记录等其它更复杂的数据类型。在程序包 Standard 中预定义了一些简单数据类型,例如Integer,Long_Integer,Float,Long_Float,Boolean,Character,Wide_Character,以及这些数据类型的运算符。下面我们除了学习上述的4种标量类型(Scalar Type)外,还要学习一下枚举类型(Enumration)。由于 Ada 中布尔型和字符型都是由枚举类型实现的,因此也可将这两种类型认为是枚举类型。2.4.1 整型(Integer)
Integer 整型
&&& 一个整型数据能存放一个整数。预定义的整型有Integer,Short_Integer,Short_Short_Integer,Long_Integer,Long_Long_Integer还有Integer的子类型 Positive ,Natural。RM95 没有规定 Integer及其它整型的具体取值范围及其位数,由编译器决定。只规定了没多大意思的最小取值范围,如要求一个Integer 至少要为16位数,最小取值范围为-3(-2 ** 15+1 .. 2**15-1)。因此还有Integer_8,Integer_16,Integer_32,Integer_64这些指定了位数的整型,以方便用户。在RM95里,也就是编译器实现里,以上类型声明格式为:
typeInteger is range implementation_defined(Long_Integer它们也一样)
subtypePositive is Integer range 1..Integer'L
subtypeNatural is Integer range 0..Integer'L (Integer'Last 表示Integer的最后一个值,即上限,见)
&&& 程序 System 里定义了整数的取值范围:
Min_Int : constant := Long_Long_Integer'F
Max_Int : constant := Long_Long_Integer'L
Modular 整型
&&& 还有一类整型是 Modular,异于上面的整型。如果将 Integer 整型与 C 中的 signed int 相类比,它们的取值范围可包括负数;那么 Modular 类型就是unsigned int,不能包含负数。其声明格式为:
typetyep_name is mod range_
&&& 其中的 range_specification 应为一个正数; type_name 的取值范围为(0..range_specification - 1)。
&&& 如下面类型 Byte:
typeByte is mod 256;
&&& 这里 Byte 的取值范围为 0 .. 255。
&&& Modular 类型在程序包 System 也有常量限制,range_specification 如是2的幂则不能大于 Max_Binary_Modulus ,如不是幂的形式则不能大于Max_Nonbinary_Modulus。 这两个常量的声明一般如下:
Max_Binary_Modulus : constant := 2 ** Long_Long_Integer'S
Max_Nonbinary_Modulus : constant := Integer'L
&&& 细心的读者可能会发现上面两个常量的值实际上是不一样的,也就是说 Modular 类型实际上有两个不同的限制。RM95 关于这点的解释是,2进制兼容机上,Max_Nonbinary_Modulus 的值大于 Max_int 很难实现。2.4.2 实型(Real)
&&& 相对于整型表示整数,实型则表示浮点数。实型分为两大类: 浮点类型(floating point) 和定点类型 (fixed point)。它们之间的区别在于浮点类型有一个相对误差;定点类型则有一个界定误差,该误差的绝对值称为 delta。下面就分类介绍这两类数据类型。浮点类型(Floating Type)
&&& 浮点类型预定义的有Float,Short_Float,Short_Short_Float,Long_Float,Long_Long_Float等,它们的声明格式入下:
type type_name is digits number [range range_specification] ;
&&& digits
type Real is digits 8;
typeMass is digits 7 range 0.0 .. 1.0E35;
subtype Probability is Real range 0.0 .. 1.0;
&&&& Real 表示精度为8位的符点数类型,它的取值范围由于没给定,实际上由编译器来决定;RM 95里关于这种情况是给出了安全范围(safe range), 取值范围是-10.0**(4*D) .. +10.0**(4*D), D 表示精度,此例中为8,所以 Real 的安全取值范围一般来说应为 -10.0E32 .. +10.0E32。
&&& Mass 是表示精度为7位的符点型,取值范围为 00.. 1.0E35;
&&& Probability 是Real的子类型,精度也是8位,取值范围 0.0..1.0;
&&& 程序包 System 定义了精度的两个上限:Max_Base_Digits 和 Max_Digits ,一般来说应为
Max_Base_Digits : constant := Long_Long_Float'(即Long_Long_Float的精度)
Max_Digits : constant := Long_Long_Float'
&&& 当range_specification指定时,所定义类型的精度不能大于 Max_Base_D当range_specification没有指定时,所定义类型的精度不能大于 Max_Digits。定点类型
&&& 定点类型主要是多了一个delta,它表示该浮点类型的绝对误差。比方说美元精确到 0.01 元(美分),则表示美元的数据类型 Dollar 的 delta 为 0.01,不像浮点型是近似到 0.01。
&&& 定点型的声明格式有两种:
普通定点型:type type_name is delta delta_number_range range_specification;
十进制定点型:type type_name is delta delta_number digits digit_number [range range_specification];
&&& 除 delta delta_number 外,各部份意义与浮点型相同。
&&& 定点型中有一个 small 的概念。定点数由一个数字的整数倍组成,这个数字就称为该定点数类型的 small。如果是普通定点型,则 small 的值可以被用户指定(见下节 数据类型属性),但不能大于该类型的 delat;如果没有指定,small 值由具体实现决定,但不能大于 delta。如果是十进制定点型,则 small 值为 delta,delta 应为 10 的幂,如果指定了该定点型的取值范围,则范围应在 -(10**digits-1)*delta..+(10**digits-1)*delta 之间。看一下下例:
type Volt is delta 0.125 range 0.0..255.0;type Fraction is delta System.Fine_Delta range -1.0..1.0;type Money is delta 0.01 digits 15;subtype Salary is Money digits 10;
2.4.3 布尔型(Boolean)
&&& 逻辑运算通常需要表示"是"和"非"这两个值,这时就需要使用布尔型。Ada 中的布尔型与 Pascal 中的类似,是 True 和 False 两个值。布尔型属于枚举数据类型,它在程序包 Standard 中定义如下:
type Boolean is (True, False);
&&& 习惯于 C 语言的朋友在这里需要注意一下,Boolean 的两个值 True,False 和整型没有什么关系,而不是 C 语言中往往将True 定义为值1,False 为2。2.4.4 字符型(Character)
&&& Ada83 最初只支持 7 位字符. 这条限制在 Ada95 制订前已经放松了,但一些老编译器如 Meridian Ada 还是强制执行. 这导致在一台PC上显示图形字符时出现问题;因此,在一般情况下,是使用整型来显示 Ascii 127以后的字符,并使用编译器厂商提供的特殊函数。
&&& 在 Ada95 里,基本字符集已由原来的ISO 646 标准的7位字符变为ISO 8859标准的8位字符,基于 Latin-1并且提供了 256 个字符位置。 Ada95 同样也支持宽字符 ISO 10646,有2**16个的字符位置。因此现代编译器能很好地处理 8 位字符和 16 位字符。
&&& 7 位字符在已经废弃的程序包 Standard.Ascii 内定义。在程序包 Standard 内预定义的字符型 Character 和 Wide_Character 分别表示Latin-1 字符集和宽字符集,类型 Wide_Character 已经包含了类型 Character 并以它作为前 256 个字符。程序包 Ada.Characters.Latin_1和Ada.Characters.Wide_Latin_1 提供了 Latin-1 字符集的可用名称,Ada.Characters.Handling 则提供一些基本的字符处理函数。具体内容见 。
&&& 从下例可以了解一下字符型:
000 -- filename: puta.adb001 with Ada.Text_IO; use Ada.Text_IO; 002 procedure puta is003 && subtype Small_Character is {'a' ,'b','c', 'd'}; 004&&& Level : Small_Character := 'a';005 begin006&&& Put ("You level is");007&&& Put (Level);008&&& New_L 009
[003] 创建了一个字符类型 Small_Character,包含 a,b,c,d四个字母;如 C 语言一样,使用字符时需加' '。
[004]声明变量 Level,类型为Small_Character,值为字母 a 。
上面这个例子主要还是说明一下字符类是怎样定义的,但 Character和Wide_Chracter 实际实现却不是这么简单。
2.4.5 枚举类型(Enumeration)
&&& 有时候我们需要一个变量能表示一组特定值中的一个。如 today 这个变量,我们希望它的值是Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday其中的一个,这时枚举类型就相当有用,上述情况中就可以创建新类型 Day,如下:
type Day is ( Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);
&&& 然后声明变量 today 的数据类型为 Day:
&&& 这样today 就能接受Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday这几个值中的任意一个。
&&& 前面提及的类型 Character ,Wide_Character,Boolean 都是枚举类型,也按照下面给出的格式声明:
type type_name is (elememt_list);
&&& element_list 需列举出该类型所有的可能值。
&&& Ada 能自动检测上下文,因此大部份情况下能分辨不同枚举数据类型下的枚举元素,如再声明一个类型 Weekend:
type Weekend is ( Saturday, Sunday);
subtype Weekend is range Saturday .. S
&&& 赋给上例中的变量 Today 值为 Sunday时,不会产生歧义;但在有些情况下,Ada 无法分辨枚举元素时则会产生问题,这时就要使用类型限制,详见
 & Ada 中的基本数据类型就讲到这里,实际上本节是基于上一节内容的扩展,说穿了还是创建数据类型。Ada 在数据类型处理上提供的强大功能在接下的章节里我们将会接触的更多,在这方面 Ada 的确比其它大部份语言做的好多了,熟悉 C ,Pascal的朋友大概会感到相当有意思。
2.5 数据类型属性 (Attributes)
&&& 数据类型属性,表示某个数据类型的具体特征---取值范围,最小值,最大值,某数在该类型中的位置 …… 应该说是相当有用的-----起码不像 C 语言,还要翻翻系统手册才能知道某个数据类型的具体定义。这些属性的用法和调用函数一样,也可以认为它们就是预定义的函数----虽然不怎么准确,关于函数,详见 ;有些返回值为通用类型(universal type)和字符串型。
&&& 数据类型的属性既可以使用预先定义的操作,也可以自己定义数据类型的属性,如S'First 是返回 S 类型的下限,如果用户不满意默认的属性,也可自己指定S'First(虽然没必要),如:
for S'First use My_Version_F
  My_Version_First 是用户自己的函数,以后当使用 S'First 时,实际上调用 My_Version_First;有些数据属性也可以直接用数字标示,如:
for S'First use 0;
  这样,S'First 的值就成了0。在很多地方,如内存管理中,这种用法还是比较普遍的。下面简单地列出标量类型的属性,S 表示某个标量类型:
2.5.1 通用标量类型属性
S'First& 返回 S 类型的下限,返回值为 S 型。
S'Last&& 返回 S 类型的上限,返回值为 S 型。
S'Range& 返回 S 类型的取值范围,即 S'First .. S'Last。
S'Base&& 表示 S 类型的一个子类型,但没有范围限制(单纯从取值范围角度讲,“儿子”反而比“父母”大),称之为基类型(base type)。
S'Min&&& 函数定义为: function (Left,Right:S'Base) return S'Base 。比较 Left和 Right 的大小,返回较小值。如:Integer'Min (1 , 2) = 1 。
S'Max&&& 函数定义为: function (Left,Right:S'Base) return S'Base 。比较 Left和 Right 的大小,返回较大值。如:Integer'Max (1 , 2) =2 。
S'Succ&& 函数定义为:function S'Succ (Arg :S'Base) return S'Base 。返回 Arg 的后趋。
S'Pred&& 函数定义为: function S'Pred (Arg :S'Base) return S'Base 。返回 Arg的前趋。
S'Wide_Image 函数定义为:function S'Wide_Image (Arg : S'Base) return Wide_String 。返回 Arg 的“像”,即可显示的字符串,这里返回宽字符串型 Wide_String。如:Float'Wide_Image (9.00) = “9.00" 。详见 。
S'Image&&&&& 与 S'Wide_Image 一样,但返回字符串型 String 。
S'Wide_Width 表示 S'Wide_Image 返回的字符串的最大长度,返回值为 universal_integer。
S'Width&&&&& 表示 S'Image 返回的字符串的最大长度,返回值为 universal_integer。
S'Wide_Value 函数定义为: function S'Wide_Value ( Arg : Wide_String) return S'Base。是 S'Wide_Image 的逆过程,返回与“像”Arg 相对应的 S 类型的值。如: Float'Wide_Value ("9.00") = 9.00 。
S'Value&&&&& 与 S'Value 一样,但参数 Arg 是 String 类型。
<span type="1" blog_id="74841" userid='
44篇文章,28W+人气,0粉丝
互联网名企晋升之道
¥51.0070人订阅
<span type="1" blog_id="74841" userid='

我要回帖

更多关于 金融机构为B类企业核注时发生错误 的文章

 

随机推荐