我有这个代码,其过程使用了重载和默认参数:
program Project2;
{$APPTYPE CONSOLE}
uses SysUtils;
procedure Foo; overload; // not actually needed to reproduce
begin
end;
procedure Foo(const a: array of string; b: Boolean=False); overload;
begin
Writeln(Length(a));
end;
begin
Foo(['1', '2', '3']); // => 1 ???
Foo(['1', '2', '3'], False); // => 3 OK
Readln;
end.
输出结果为:
1
3
请注意,对Foo
的第一次调用不提供默认值。为什么会这样?这个问题只与很老的编译器有关吗?
只有在使用overload
密钥时才会发生这种情况。
procedure Foo2(const a: array of string; b: Boolean=False);
begin
Writeln(Length(a));
end;
Foo2(['1', '2', '3']);
工作正常。
答案 0 :(得分:4)
这显然是 Delphi-5 中的错误。只有在满足以下条件时才会发生:
该程序标有overload
array of string
是第一个参数
没有将默认参数传递给过程
答案 1 :(得分:2)
正如您所发现的那样,David帮助澄清:这是Delphi 5中的一个错误(可能还有那个时代的其他几个版本)。在特定条件下,编译器无法正确调用该过程。
这实际上是两个特征的冲突:
High
索引),以便该方法可以正确地确定数组中元素的数量。High
索引,并在其位置传递默认值。我确定您已经在使用明显的解决方法,但我将其包含在内是为了完整性。当我以前在Delphi 5中工作时,我们替换了 array of String
的所有组合,并默认使用以下内容;
(无论我们是否已经使用 overload
)。
procedure Foo(const a: array of string; b: Boolean); overload; {Remove the default}
begin
...
end;
procedure Foo(const a: array of string); overload;
begin
Foo(a, False); {And pass the default value via overload}
end;
您可以通过在CPU窗口中调试( Ctrl + Alt + C < kbd>)并检查汇编代码。
您应该能够推断出Foo
过程已编译为期望:
Foo
eax
ecx
High
索引
注意我使用edx
默认值来获得更具特色的默认值。
Integer
procedure Foo(const a: array of string; b: Integer = 7);
...
Foo(['a', 'b', 'c']);
{The last few lines of assembler for the above call}
lea eax,[ebp-$18] {Load effective address of array}
mov ecx,$00000007 {Implicitly set default value 7}
mov edx,$00000002 {The hidden High value of the open array}
call Foo
procedure Foo(const a: array of string; b: Integer = 7); overload;
...
Foo(['a', 'b', 'c']);
lea eax,[ebp-$18]
{The second parameter is now uninitialised!}
mov edx,$00000007 {Instead the default is assigned to register for High(a)}
call Foo
1)正如上面的案例2中所指出的,当错误显示时,procedure Foo(const a: array of string; b: Integer = 7); overload;
...
Foo(['a', 'b', 'c'], 5);
lea eax,[ebp-$18]
mov ecx,$00000005 {The explicit argument for 2nd parameter}
mov edx,$00000002 {The hidden parameter is again correctly assigned}
call Foo
未被初始化。以下内容应证明效果:
ecx
2)动态数组不会出现错误。动态数组的长度是其内部结构的一部分,因此不能忘记。