5
program TypeCategory;
{$R+}
var
    sInt : shortint;
    iInt : integer;
begin
    readln(iInt);
    sInt := iInt;
    writeln(sInt);
end.

考虑到上面的例子,pascal 语言确实允许从integerto赋值shortint,甚至longint可以在shortint没有显式类型转换的情况下赋值。也就是说,pascal 允许在类型类别内赋值(这里是整数类型)。

Pascal 以它而闻名strongly typed,但为什么它允许这种weakly typed事情呢?我认为这种语法会鼓励不一致的代码。

这种语法有什么优点?除了著名的 C 和 C++,还有其他语言应用这种语法吗?

谢谢。

编辑
我只测试过turbo pascalfree pascal with fpc/objfpc/tp/delphi model而且,gcc/g++msvc产生相同的结果。也就是说,从int(我的计算机上的大小为 4 字节)到short int(大小为 2)的分配不会触发任何编译错误,而你可以设置proper options to make the compilers generate possible lose of datawarnings.

4

5 回答 5

8

第 1 部分。关于定义

首先,您将什么语言和实现称为“pascal”?如果您谈论的是ISO Pascal,那么它在很多年前就已经死了。如果您在谈论其他语言或实现,请提供更多信息。

其次(正如 Teun D 已经提到的),术语强类型没有定义。查看有关强类型的 Wikipedia 文章

然而,在计算的短暂历史中,这些术语被赋予了如此广泛的含义,以至于通常很难脱离上下文了解单个作者在使用它们时的含义。

假设我们遵循 Luca Cardelli 的文章 Typeful Programming 在维基百科页面上描述的定义:

Luca Cardelli 的文章 Typeful Programming 将强类型简单地描述为没有未经检查的运行时类型错误。换句话说,没有未经检查的运行时错误被称为安全性或类型安全性;托尼霍尔的早期论文称这种财产安全。

无论如何,所描述的行为不能归类为静态(或安全)类型规则。我个人真的不喜欢这个嗯......嗯,这不是一个功能,这是一个错误。=)

第 2 部分。答案

我认为问题不在于这种弱类型,而在于某些语言中可用的多种整数类型。

除了著名的 C 和 C++ 之外,还有其他语言应用这种语法吗?

我认为几乎所有具有各种整数类型的静态类型语言都有这种行为。早年拥有这些 SHORTINT 和所有爵士乐以节省内存是个好主意。但是现在几乎每台 PC 都有大约 1 GB 和更多的 RAM...假设我们有 100 万个 4 字节整数而不是 2 字节 SHORTINT。它只有大约 4 MB 的 RAM,而不是 2 MB。我认为没有您描述的所有这些奇怪行为是合理的价格。

快速浏览一下 Wirth 的 Oberon-07(语言报告,PDF)。只有一种整数类型 - 32 位 INTEGER。

也可以提到具有 int 类型的 Python(或者可能是其他一些现代动态类型语言),它表示无限范围内的数字,仅受可用(虚拟)内存的影响。

所以你可以看到趋势——各种整数类型是 70 年代的生存之道。=)

这种语法有什么优点?

优点是(可能)减少了冗长。这种静态类型语言已经非常冗长,所以如果我们决定像 Wirth 在 Oberon-2 中所做的那样添加一些显式整数类型转换(看看 SHORT() 和 LONG() 函数),它们会变得更加冗长。作为一种折衷方案,可以允许隐式转换。同样在许多语言中,整数类型变量的实际大小并不固定,并且从一种实现到另一种实现不同。唯一可用的信息是 size(shortint) <= size(int)。在相等的情况下,显式转换看起来很奇怪。

第 3 部分。酒神颂到 Oberon-2 =)

顺便说一句,不要对帕斯卡过于警惕。它已经死了,但在Oberon-2 Niklaus Wirth 纠正了他的错误。

在语言报告的第 6 章中,您可以找到有关类型的信息。对于我们的讨论,重要的声明是:

类型 3 到 5 是整数类型,类型 6 和 7 是实类型,它们一起被称为数字类型。它们形成一个层次结构;较大的类型包括较小的类型(的值): LONGREAL >= REAL >= LONGINT >= INTEGER >= SHORTINT

第 9 章中,我们可以阅读有关作业的内容:

表达式必须与变量赋值兼容

最后在附录 A 中:

分配兼容

如果满足以下条件之一,则 Te 类型的表达式 e 是与 Tv 类型的变量 v 兼容的赋值:

Te和Tv是同一类型;

Te 和 Tv 是数字类型,Tv 包括 Te

...

所以我们在这里。您不能将 INTEGER 表达式分配给 SHORTINT 变量。如果您有兴趣,还可以查看Component Pascal,Oberon-2 的次要变体和改进。BlackBox Component Builder是一个适用于 Windows 的 IDE。


回应贾斯汀史密斯的评论。

我很惊讶他说较大的类型包括较小的类型(的值):LONGREAL >= REAL >= LONGINT >= INTEGER >= SHORTINT,因为有些 LONGINTS 不能表示为“REAL”。

我对你的说法有点困惑

有些 LONGINTS 不能表示为“REAL”

实际上在我上面提到的机器IDE上有

MAX(LONGINT) = 9223372036854775807

MAX(REAL) = 1.797693134862316E+308

因此,您可以将每个 LONGINT 表示为 REAL 数。但表示可能并不准确。我认为您实际上是在谈论它,但我们在这里谈论的是不同的整数类型转换。REAL 和 INTEGER 之间的转换是另一回事。糟糕而令人困惑的命名的故事。从数学的角度来看,REAL 数字实际上并不是实数。它们是一些近似表示。可以使用有理数逼近(将分子和分母存储为整数),但常用的方法是使用浮点逼近。IEEE 浮点算术标准(也称为 IEEE 754)是最广泛使用的浮点计算标准。

每个人都应该知道 REAL 数字不是实数,而是 IEEE 754 标准中描述的数字。每个人都应该阅读“每个计算机科学家应该知道的关于浮点运算的知识”以澄清一些观点。

但这是另一个故事... =)

于 2010-01-22T20:20:07.400 回答
2

无论使用哪种语言,程序员总有办法自取其辱。使用变量时,您需要了解要存储的数据类型以及如何使用它。强类型化使这更安全,但您仍然可能错误地将较大的变量转换为较小的变量。

于 2010-01-22T20:25:22.170 回答
0

我认为这种行为不是弱类型,因为您永远无法获得指向shortint真正指向 a的 a 的指针integer。它也永远不会导致崩溃(尽管第二个变量中的数值可能与您的预期不同)。

你的意思是,显然,帕斯卡不检查溢出。在例如。C#,您可以从代码 ( http://msdn.microsoft.com/en-us/library/khy08726(VS.71).aspx ) 设置检查行为,但出于性能考虑,通常不会这样做。我认为这也适用于帕斯卡。

于 2010-01-17T16:36:21.327 回答
0

如果一种语言不允许从 int 分配到 short int,那么就不可能编写此代码

var
sInt : shortint;
iInt : integer;

if (iInt < 100 && iInt > -100)
{
   sInt := iInt; // this would not compile
}

或这个

var
sInt : shortint;
iInt : integer;

sInt := (iInt & 0xFFFF); // this would not compile

在像这样对短整数进行数学运算时,您不能编写将整数用作临时值的代码。

var
sInt1 : shortint;
sInt2 : shortint;
iInt : integer;

/* I want to multiply sInt2 by sInt1 and then divide by 100 */
iInt = sInt2;
sInt2 := (iInt * sInt1) / 100; // this would not compile

但是在临时值中使用更多位是一种常用技术,可确保您不会因临时值溢出而出错。

于 2010-01-27T00:41:27.300 回答
0

据我所知,有几点需要考虑:

  1. 在经典的帕斯卡意义上,只有一种整数类型,整数。其他只是子范围,因此不是严格意义上的完全独立的类型。根据范围允许分配,并且运行时范围检查是强制执行它的标准的一部分。
  2. 一般来说,只要范围匹配,Pascal 就允许为数字类型赋值。这就是允许将整数添加到实数的原因。(real 被认为包含整数的范围),但不是相反。不过,这是一个特殊的例外(为便于使用而定义的语言转换),因为 real 甚至不是序数类型。

Classic Pascals 经常定义与机器字长不同的基本整数类型。(通常是两倍大),到机器上可以处理的最大类型,并为所有变量类型使用子范围。这意味着即使偶尔超过机器字长,各种计算,运行时和编译时(常量)都将保持工作,但会牺牲一些性能。它们只会被升级为更大的整数类型。我只是从新闻组那里得到的,不过这方面的经验并不多。我不知道是否有任何乘法被自动放大。可能这在当今不太适用,因为大多数处理不是通过定义明确的输入和工程师来处理的批量处理。

将范围放在所有变量上使范围检查也更有效

例如

var x : 0..10;

x:=10;
x:=x+1; // runtime range check error  here.

然而,随着 DOS 时代引入了一种更随意的程序员,这种使用子范围来定义变量的做法已经减弱。在 Turbo Pascal 中,几乎所有内容都输入了“整数”,因此出于效率原因,它必须是机器字(或更小)。

必须引入两倍于范围大小的 longint(后来在 Delphi 中引入了 int64。也许及时为 x86_64 引入了 int128),但这总是有些特殊(并且正常的范围规则不适用。还有对应的无符号类型的问题到最大的有符号类型从未完全解析(因为 Pascal 基类型是有符号的,因此不能包含最大的无符号类型)

于 2013-04-21T13:50:48.647 回答