为什么Delphi和Free Pascal通常更喜欢有符号整数数据类型而不是无符号数据类型?

为什么Delphi和Free Pascal通常更喜欢有符号整数数据类型而不是无符号数据类型?,delphi,pascal,freepascal,Delphi,Pascal,Freepascal,我不是Pascal新手,但直到现在我仍然不知道为什么,通常将参数和返回值声明为有符号整数,而我认为它们应该始终为正。例如: Pos()返回整数的类型。可能是否定的吗 SetLength()将NewLength参数声明为整数类型。字符串是否有负长度 System.THandle声明为Longint。句柄有负数吗 在Delphi和Free Pascal中有许多类似的决策。这背后的考虑因素是什么?首先,THandle的声明是错误的。它在Windows标题中是未签名的,在Delphi中应该是未签名的

我不是Pascal新手,但直到现在我仍然不知道为什么,通常将参数和返回值声明为有符号整数,而我认为它们应该始终为正。例如:

  • Pos()
    返回整数的类型。可能是否定的吗
  • SetLength()
    NewLength
    参数声明为整数类型。字符串是否有负长度
  • System.THandle
    声明为Longint。句柄有负数吗

在Delphi和Free Pascal中有许多类似的决策。这背后的考虑因素是什么?

首先,THandle的声明是错误的。它在Windows标题中是未签名的,在Delphi中应该是未签名的。事实上,我认为这在Delphi的最新版本中得到了纠正

我想,人们对签名的偏好在很大程度上是历史性的,而不是特别重要。然而,我可以想出一个例子,说明这一点很重要。考虑for循环:

for i := 0 to Count-1 do
如果
i
为无符号且
Count
为0,则此循环从0运行到
$FFFFFFFF
,这不是您想要的。使用有符号整数循环变量可以避免该问题

Pascal是其语法的牺牲品。等效C或C++循环没有这样的麻烦

for (unsigned int i=0; i<Count; i++)
for(无符号整数i=0;i
  • 一些与字符串相关的搜索函数在未找到任何内容时返回-1
  • 我相信这背后的原因是MaxInt是2GB,这是32位Delphi中字符串的最大大小
    • 在帕斯卡语中,整数(有符号)是基本类型。所有其他整数类型都是整数的子范围。(这在博尔兰方言中并不完全正确,在TP中是longint,在Delphi中是int64,但足够接近)

      这其中的一个重要原因是,如果计算的中间结果为负数,并且使用无符号整数进行计算,则会触发范围检查错误,而且由于大多数较旧的编程语言不采用2-补码整数,因此(在范围检查关闭的情况下)结果甚至可能会损坏

      THandle的情况要简单得多。Delphi在D4之前没有合适的32位无符号整数,只有31位基数。(因为32位无符号整数不是整数的子范围,后面的无符号整数是int64的子集,这将问题转移到uint64,uint64仅在D2010左右添加)

      因此,在标题中的许多地方,在winapi使用无符号类型的地方使用有符号类型,这可能是为了避免在这些版本中第32位意外损坏,以及自定义类型被卡住

      但是winapi案例不同于一般案例

      稍后添加一些Pascal(和Modula2/3)实现通过将整数设置为大于字号的大小来绕过此陷阱,并要求所有数字类型声明正确的子范围,如下面的程序所示

      第一种方法的基本假设是所有操作都是整数的子集,第二种方法允许编译器再次缩小几乎所有操作以适应寄存器,特别是当CPU有一些大于字的操作时。(如x86,其中32位*32位mul给出64位结果,或者可以使用状态位检测字号溢出(例如,在不进行完整的2*字号添加的情况下为添加生成范围异常)


      Turbo Pascal和Delphi模拟16位和32位产品的字号两倍的整数类型。对最高无符号类型的处理充其量也很粗糙。

      使用有符号整数有很多原因,甚至在不打算返回负值时也可能适用

      假设我编写了调用Pos的代码,我想对结果进行数学运算。您是希望得到一个负结果
      (Pos('x',s)-5)
      引发一个范围检查异常,下溢并成为一个大约40亿左右的非常大的无符号数,还是变为负数,如果
      Pos('x',s)
      返回
      1
      ?对于很少考虑这些情况的新用户来说,任何一个都是问题的根源,但长期以来的传统是,通过使用
      整数
      结果,您的工作就是检查负结果和零结果,而不是将它们用作字符串偏移量。开始和结束都有好处高级程序员在使用整数时,如果没有“负”值,则会滚下并成为大的无符号值或引发范围异常

      其次,请记住,在开始编程时,通常会引入
      整数
      (带符号)类型早在引入无符号类型(如
      Cardinal
      )之前就已经存在了。初学者通常使用
      Pos
      等函数,并且使用会产生最不友好的副作用的类型是有意义的。范围大于您绝对需要的范围不会产生负面副作用(在delphi中,Pos可能需要的范围是1到最大字符串长度)。在32位delphi中,为Pos使用
      Cardinal
      类型没有任何好处,选择它肯定有缺点


      然而,一旦你使用64位delphi,理论上你可以拥有比整数更大的字符串,移动到基数并不能解决你所有的潜在问题。然而,任何人拥有2+GB字符串的可能性可能为零,而且delphi 64位编译器无论如何不允许
      >2 GB
      字符串。在我的测试中,我可以在64位Delphi中,我有一个几乎1 GB的字符串。因此Win64字符串的实际长度限制约为10亿(1073741814)个字符,这使用了将近2 GB的实际RAM。在这个限制下,我要么得到
      EIntOverflow
      要么
      EAccessViolation
      ,似乎我正在访问Delphi运行时库(RTL)错误,未正确定义限制,因此您的里程可能会有所不同。

      FPC考虑很简单:与Delphi兼容。
         var x : 0..20;
             y : -10..10;
             
         begin
           // any expression of x and y has a range -10..20