【问题标题】:How does Delphi resolve overloaded functions with integral parameters?Delphi如何解决带整数参数的重载函数?
【发布时间】:2012-09-13 15:43:36
【问题描述】:

考虑以下程序:

program IntegerOverloads;
{$APPTYPE CONSOLE}

procedure WordOrCardinal(Value: Word); overload;
begin
  Writeln('Word');
end;

procedure WordOrCardinal(Value: Cardinal); overload;
begin
  Writeln('Cardinal');
end;

procedure SmallintOrInteger(Value: Smallint); overload;
begin
  Writeln('Smallint');
end;

procedure SmallintOrInteger(Value: Integer); overload;
begin
  Writeln('Integer');
end;

procedure ShortintOrSmallint(Value: Shortint); overload;
begin
  Writeln('Shortint');
end;

procedure ShortintOrSmallint(Value: Smallint); overload;
begin
  Writeln('Smallint');
end;

procedure Main;
var
  _integer: Integer;
  _cardinal: Cardinal;
  _word: Word;
begin
  WordOrCardinal(_Integer);
  SmallintOrInteger(_cardinal);
  ShortintOrSmallint(_word);
end;

begin
  Main;
  Readln;
end.

XE2编译时的输出为:

Cardinal
Integer
Smallint

Delphi 6 编译时的输出为:

Word
Smallint
Shortint

documentation 状态(强调我的):

你可以传递给一个重载的例程参数,这些参数不是 与任何例程声明中的类型相同,但 与多个参数中的参数赋值兼容 宣言。当例程超载时,这种情况最常发生 具有不同的整数类型或不同的实数类型 - 例如:

procedure Store(X: Longint); overload;
procedure Store(X: Shortint); overload;

在这些情况下,如果可以做到没有歧义, 编译器调用其参数为 类型的例程 容纳调用中实际参数的最小范围

但这似乎适用于此。示例代码中的所有过程调用都不接受容纳调用中实际参数的类型。

我找不到任何描述编译器遵循什么规则的文档。谁能指点我这些文档?

这个问题是由以下文章提示的:


更新

在 Ken White 的 cmets 的提示下,我编写了另一个程序来说明更多的奇怪之处:

program IntegerOverloadsPart2;
{$APPTYPE CONSOLE}

procedure Test(Value: Byte); overload;
begin
  Writeln('Byte');
end;

procedure Test(Value: Word); overload;
begin
  Writeln('Word');
end;

procedure Test(Value: Cardinal); overload;
begin
  Writeln('Cardinal');
end;

procedure Test(Value: Uint64); overload;
begin
  Writeln('Uint64');
end;

procedure Main;
var
  _byte: Byte;
  _shortint: Shortint;
  _word: Word;
  _smallint: Smallint;
  _cardinal: Cardinal;
  _integer: Integer;
  _uint64: UInt64;
  _int64: Int64;
begin
  Writeln('Unsigned variables passed as parameters:');
  Test(_byte);
  Test(_word);
  Test(_cardinal);
  Test(_uint64);
  Writeln;
  Writeln('Signed variables passed as parameters:');
  Test(_shortint);
  Test(_smallint);
  Test(_integer);
  Test(_int64);
end;

begin
  Main;
  Readln;
end.

XE2 编译时输出为:

Unsigned variables passed as parameters:
Byte
Word
Cardinal
Uint64

Signed variables passed as parameters:
Uint64
Uint64
Uint64
Uint64

在 Delphi 6 上,我必须删除 UInt64 重载,因为 Delphi 6 上不存在该类型,输出为:

Unsigned variables passed as parameters:
Byte
Word
Cardinal

Signed variables passed as parameters:
Byte
Byte
Byte

再一次,这两种行为看起来都与以下陈述一致:

在这些情况下,如果可以做到没有歧义, 编译器调用其参数为 类型的例程 容纳调用中实际参数的最小范围

【问题讨论】:

  • 你如何理解“范围”?如果您将其视为“Word 和 Smallint 都有 65536 个不同的值”,则 XE2 输出与文档匹配。如果您将其视为“Word 的范围从 0 到 65535,Smallint 的范围从 -32768 到 32767”,那么据我所知,根据您链接到的文档,没有正确的答案。
  • @hvd 我的解释是你描述的第二个。
  • +1。好问题。起初我认为这与分配给每个变量的不同值有关,但对它们的一些实验表明情况并非如此。 (为_word 分配一个非常小的值不会改变它从SmallInt 的大小,并且一个非常大的值也保持不变。)我想知道这是否与对 32/64 位支持所做的更改有关?跨度>
  • @ken “起初我认为这与分配给每个变量的不同值有关” 这引发了一个有趣的话题。数据流分析。 Delphi 编译器不做任何事情。所以如果你写 i := 1;如果 i > 0 则编译器将在运行时检查不等式。编译器根本不做数据流分析。我认为这不是坏事。完全没有批评。
  • 实际上,XE2 的行为是有道理的;我认为早期版本是错误的。使用 32 位的 Integer 调用 WordOrCardinal 应该调用 Cardinal 版本,除非有关于该值的任何编译时信息,因为不能假定 32 位 Integer 适合16 位 Word。这同样适用于 ShortintOrSmallInt(_word),其中 16 位 Word 不可能被假定为适合 8 位 ShortInt,因此它解析为 SmallInt。它可能会导致运行时范围检查或溢出异常,但在编译时没有需要考虑的价值。我错过了什么吗?

标签: delphi


【解决方案1】:

无符号类型都不能容纳有符号类型;引用的文档与您的示例一致 - 它只是没有说明编译器将如何处理它们。另一方面,有符号类型可以容纳无符号类型(SmallInt 容纳 Byte,LongInt 容纳 Word,Int64 容纳 Cardinal):

program IntegerOverloadsPart3;
{$APPTYPE CONSOLE}

procedure Test(Value: ShortInt); overload;
begin
  Writeln('Short');
end;

procedure Test(Value: SmallInt); overload;
begin
  Writeln('Small');
end;

procedure Test(Value: LongInt); overload;
begin
  Writeln('Long');
end;

procedure Test(Value: Int64); overload;
begin
  Writeln('64');
end;

procedure Main;
var
  _byte: Byte;
  _word: Word;
  _cardinal: Cardinal;
  _uint64: UInt64;
begin
  Writeln('Unsigned variables passed as parameters:');
  Test(_byte);
  Test(_word);
  Test(_cardinal);
  Test(_uint64);
  Writeln;
end;

begin
  Main;
  Readln;
end.

Delphi XE 输出:

Small
Long
64
64

【讨论】:

  • 是的,这一切都是有意义的,将无符号变量传递给采用有符号参数的过程。反过来就麻烦了。
  • @DavidHeffernan - 如果您正在编写重载,为什么不多写一些(用于有符号类型)来消除所有歧义?
  • 我不是在写这样的代码。我认为这是一个雷区。 Jolyon 的博客文章让我开始思考,我想了解编译器为什么会这样。
  • 是的,它是一个雷区,即使编译器工程师会解释为什么编译器会这样,它仍然是一个雷区。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多