文档中说:
此外,避免将字符串索引作为变量参数传递,因为这会导致低效的代码。
但我认为这并不总是正确的。在一个足够简单的例子中,优化器会尽其所能。在我看来,这是一种微观优化,不应该在编写代码时困扰你。参见Jeff Atwood:
这真的无关紧要!这真的无关紧要!
让我们看一个例子:
procedure StringIndexByVar(const S: string; var I: integer);
begin
I := 1;
while I <= Length(S) do
begin
Write(S[I]);
inc(I);
end
end;
procedure StringIndexByLocal(const S: string; var I: integer);
var
LIndex: integer;
begin
LIndex := 1;
while LIndex <= Length(S) do
begin
Write(S[LIndex]);
inc(LIndex);
end;
I := LIndex;
end;
这段代码在Win32下编译后为:
StringIndexByVar:
00417ACC 53 push ebx
00417ACD 56 push esi
00417ACE 8BDA mov ebx,edx
00417AD0 8BF0 mov esi,eax
00417AD2 C70301000000 mov [ebx],$00000001
00417AD8 EB1D jmp $00417af7
00417ADA 8B03 mov eax,[ebx]
00417ADC 0FB75446FE movzx edx,[esi+eax*2-$02] <--- (1)
00417AE1 A18CC54100 mov eax,[$0041c58c]
00417AE6 E8E9D2FEFF call @Write0WChar
00417AEB E824CCFEFF call @Flush
00417AF0 E88FC6FEFF call @_IOTest
00417AF5 FF03 inc dword ptr [ebx] <--- (2)
00417AF7 8BC6 mov eax,esi
00417AF9 E8C2F2FEFF call @UStrLen
00417AFE 3B03 cmp eax,[ebx]
00417B00 7DD8 jnl $00417ada
00417B02 5E pop esi
00417B03 5B pop ebx
00417B04 C3 ret
StringIndexByLocal:
00417B08 53 push ebx
00417B09 56 push esi
00417B0A 57 push edi
00417B0B 8BFA mov edi,edx
00417B0D 8BF0 mov esi,eax
00417B0F BB01000000 mov ebx,$00000001
00417B14 EB1A jmp $00417b30
00417B16 A18CC54100 mov eax,[$0041c58c]
00417B1B 0FB7545EFE movzx edx,[esi+ebx*2-$02] <---(1)
00417B20 E8AFD2FEFF call @Write0WChar
00417B25 E8EACBFEFF call @Flush
00417B2A E855C6FEFF call @_IOTest
00417B2F 43 inc ebx
00417B30 8BC6 mov eax,esi
00417B32 E889F2FEFF call @UStrLen
00417B37 3BD8 cmp ebx,eax
00417B39 7EDB jle $00417b16
00417B3B 891F mov [edi],ebx
00417B3D 5F pop edi
00417B3E 5E pop esi
00417B3F 5B pop ebx
00417B40 C3 ret
据我所理解,这里的字符串索引并没有区别,因为索引被加载到了
ebx
寄存器中(标有箭头1)。增加循环计数器(箭头2)需要进行内存访问,但这与字符串索引的计算无关。