我有这个代码,有一个使用重载和默认参数的过程:
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']);
工作良好。
最佳答案
概括
正如您所发现的,David 已帮助澄清:这是 Delphi 5 中的一个错误(可能还有那个时代的其他几个版本)。在特定条件下,编译器无法正确调用该过程。
它本质上是两个功能的冲突:
High
索引),以便该方法可以正确确定数组中的元素数量。 High
索引 ,并在其位置传递默认值。 解决方法
我确定您已经在使用明显的解决方法,但为了完整起见,我将其包含在内。当我以前在 Delphi 5 中工作时,我们将
array of String
和 default 的所有组合替换为以下内容;(无论我们是否已经在使用
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) 并检查汇编代码来准确观察编译器如何无法正确调用
Foo
。您应该能够推断
Foo
过程被编译为预期:eax
中开数组的地址 ecx
High
中数组的 edx
索引 注意我使用
Integer
default 作为更独特的默认值。情况1
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
案例3
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
其他观察
1) 正如上面的情况 2 所指出的,当错误出现时,
ecx
未初始化。以下应证明效果:procedure Foo(const a: array of string; b: Integer = 2); overload;
var
I: Integer;
begin
for I := Low(a) to High(a) do Write(a[I]);
Writeln(b);
end;
...
Foo(['a', 'b', 'c'], 23); {Will write abc23}
Foo(['a', 'b', 'c']); {Will write abc, but the number probably won't be 2}
2)该错误不会在动态数组中表现出来。动态数组的长度是其内部结构的一部分,因此不能忘记。
关于delphi - 使用带有默认参数和重载过程的字符串数组,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47980067/