以下代码给出了堆栈溢出:
function Func(x : Double) : Double; overload;
function Func(x : Integer) : Double; overload;
function Func(x : Double) : Double;
begin
Result := Func(Round(x));
end;
function Func(x : Integer) : Double;
begin
Result := 1.0;
end;
从不调用Integer
重载函数,Double
重载函数调用自身,直到堆栈溢出。
以下代码按预期工作:
function Func2(x : Double) : Double; overload;
function Func2(x : Integer) : Double; overload;
function Func2(x : Double) : Double;
var
ix : Integer;
begin
ix := Round(x);
Result := Func(ix);
end;
function Func2(x : Integer) : Double;
begin
Result := 1.0;
end;
这是编译器错误还是预期行为?
我怀疑这是意料之中的。
问题是编译器内部函数Round
返回一个 64 位整数。CodeInsight和官方文档都告诉我这一点。如果编译器必须在采用 32 位整数或双精度的例程之间进行选择,则当给定 64 位整数时,它会选择接受双精度的例程。
要验证这一点,请尝试
procedure Test(x: Double); overload;
begin
ShowMessage('double');
end;
procedure Test(x: Integer); overload;
begin
ShowMessage('integer');
end;
procedure TForm5.FormCreate(Sender: TObject);
begin
Test(Int64.MaxValue)
end;
System.Round 函数生成一个Int64
值。
我认为编译器保留了Func
函数的Double
重载比Integer
重载更合适。
事实上,如果参数的值超过Integer
的类型 min-max(从 -2147483648 到 2147483647,请参阅 System.Integer(,则Integer
重载可能会导致信息丢失。
将Integer
参数更改为Int64
参数将解决问题并避免信息丢失。
function Func(x : Double) : Double; overload;
function Func(x : Int64) : Double; overload;
...
function Func(x : Double) : Double;
begin
Result := Func(Round(x));
end;
function Func(x : Int64) : Double;
begin
Result := 1.0;
end;