在Delphi中检查空字符串的更好方法是什么?

24

所有程序都应该检查字符串是否为空,这是一种常见的条件。

请看下面的语句:

(1)

if Length(Str)=0 then
  // do something

(2)

:这段文字无法翻译,因为它没有上下文信息。请提供更多的上下文或问题以便进行更精确的翻译。
if Str='' then
  // do something

2
没什么大不了的,如果你问我。它们做的事情完全相同,没有一个比另一个更快。 - Andreas Rejbrand
8
第二个似乎生成的代码较少(只有一条CMP指令)。 - Sertac Akyuz
2
@SertacAkyuz:实际上,我认为它们会产生相同的代码。但是,我真的不认为性能是一个问题。 - Andreas Rejbrand
4
我认为主要的观点缺失了:更好是什么意思?它是指性能还是可读性/可维护性,因为在算法方面它们在语义上是等价的。 - Francesca
1
@Whiler - 实际上(要查找的文本:)length\({.*}\).*=.*0,可以在Delphi IDE的“替换文本”对话框中使用\0 = ''进行替换。 - Gerry Coll
显示剩余6条评论
3个回答

46
在XE2中,对于Ansi和Unicode字符串,在条件语句if str = ''中编译器能够生成更快的代码。对于Wide字符串,在条件语句if Length(str) = 0中编译器能够生成更快的代码。
测试程序:
{$A8,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N-,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y+,Z1}
program Project172;

{$APPTYPE CONSOLE}

{$R *.res}

var
  sa1,sa2: AnsiString;
  sw1,sw2: WideString;
  su1,su2: UnicodeString;

begin
  if Length(sa1) = 0 then
    ;
  if sa2 = '' then
    ;
  if Length(sw1) = 0 then
    ;
  if sw2 = '' then
    ;
  if Length(su1) = 0 then
    ;
  if su2 = '' then
    ;
end.

编译后的代码:

Project172.dpr.14: if Length(sa1) = 0 then
004050E2 A19C9B4000       mov eax,[$00409b9c]
004050E7 85C0             test eax,eax
004050E9 7405             jz $004050f0
004050EB 83E804           sub eax,$04
004050EE 8B00             mov eax,[eax]
004050F0 85C0             test eax,eax

Project172.dpr.16: if sa2 = '' then
004050F2 833DA09B400000   cmp dword ptr [$00409ba0],$00

Project172.dpr.18: if Length(sw1) = 0 then
004050F9 A1A49B4000       mov eax,[$00409ba4]
004050FE 85C0             test eax,eax
00405100 7407             jz $00405109
00405102 83E804           sub eax,$04
00405105 8B00             mov eax,[eax]
00405107 D1E8             shr eax,1
00405109 85C0             test eax,eax

Project172.dpr.20: if sw2 = '' then
0040510B A1A89B4000       mov eax,[$00409ba8]
00405110 33D2             xor edx,edx
00405112 E839E8FFFF       call @WStrEqual

Project172.dpr.22: if Length(su1) = 0 then
00405117 A1AC9B4000       mov eax,[$00409bac]
0040511C 85C0             test eax,eax
0040511E 7405             jz $00405125
00405120 83E804           sub eax,$04
00405123 8B00             mov eax,[eax]
00405125 85C0             test eax,eax

Project172.dpr.24: if su2 = '' then
00405127 833DB09B400000   cmp dword ptr [$00409bb0],$00

如果禁用优化,则差异会更大。

Project172.dpr.14: if Length(sa1) = 0 then
004050E2 A19C9B4000       mov eax,[$00409b9c]
004050E7 8945EC           mov [ebp-$14],eax
004050EA 837DEC00         cmp dword ptr [ebp-$14],$00
004050EE 740B             jz $004050fb
004050F0 8B45EC           mov eax,[ebp-$14]
004050F3 83E804           sub eax,$04
004050F6 8B00             mov eax,[eax]
004050F8 8945EC           mov [ebp-$14],eax
004050FB 837DEC00         cmp dword ptr [ebp-$14],$00

Project172.dpr.16: if sa2 = '' then
004050FF 833DA09B400000   cmp dword ptr [$00409ba0],$00

Project172.dpr.18: if Length(sw1) = 0 then
00405106 A1A49B4000       mov eax,[$00409ba4]
0040510B 8945E8           mov [ebp-$18],eax
0040510E 837DE800         cmp dword ptr [ebp-$18],$00
00405112 740D             jz $00405121
00405114 8B45E8           mov eax,[ebp-$18]
00405117 83E804           sub eax,$04
0040511A 8B00             mov eax,[eax]
0040511C D1E8             shr eax,1
0040511E 8945E8           mov [ebp-$18],eax
00405121 837DE800         cmp dword ptr [ebp-$18],$00

Project172.dpr.20: if sw2 = '' then
00405125 A1A89B4000       mov eax,[$00409ba8]
0040512A 33D2             xor edx,edx
0040512C E81FE8FFFF       call @WStrEqual

Project172.dpr.22: if Length(su1) = 0 then
00405131 A1AC9B4000       mov eax,[$00409bac]
00405136 8945E4           mov [ebp-$1c],eax
00405139 837DE400         cmp dword ptr [ebp-$1c],$00
0040513D 740B             jz $0040514a
0040513F 8B45E4           mov eax,[ebp-$1c]
00405142 83E804           sub eax,$04
00405145 8B00             mov eax,[eax]
00405147 8945E4           mov [ebp-$1c],eax
0040514A 837DE400         cmp dword ptr [ebp-$1c],$00

Project172.dpr.24: if su2 = '' then
0040514E 833DB09B400000   cmp dword ptr [$00409bb0],$00

1
“更好”指的是更高效。 - David Heffernan
3
是的。我同意你的观点,if str = '' 更易读,我从不使用 if Length(str) = 0 - gabr
2
最让我惊讶的是在使用 if sw2 = '' 时调用了 @WStrEqualWideString。而我经常使用 WideString,所以这对我来说真的是一个很好的信息。 - kobik
汇编指令的数量在性能测试中并不意味着什么(某些指令比其他指令更快)。为了获得真实的性能结果,您可以做的最好的事情是对每个解决方案进行基准测试。但即使这种解决方案也很奇怪:生成语义等效的高级指令的更好代码取决于编译器而不是程序员。 - Diego Queiroz

24

从语义上讲,它们是相同的,不会有明显的性能差异。因此,我们需要考虑代码的可读性。

if Str='' then

在我看来,可读性更好的版本就是这样。看看你的问题标题:

什么是检查空字符串的更好方法?

在你的脑海中,你将该问题视为空字符串,而不是长度为0的字符串。因此,编写与你的观点相匹配的代码。


@Smasher 看起来选民们更喜欢过早的微观优化......;-) - David Heffernan
2
我给你点赞,任何看起来更易读且与等效的代码性能相同的东西都是好事。 - user1175743
4
@David,我认为选民对详细的精度和代码印象深刻。但真正的问题应该是你应该想要哪种“更好”。这让你的回答在我的看法中更有价值(尽管我感谢Gabr提供额外的信息)。 - Francesca
1
我使用“if Str = EmptyStr”,但我认为这是个人偏好的问题。 - Alan Clark
@AlanClark:虽然时间可能微不足道,但是存在差异。我已经添加了更多关于与Empty(|Ansi|Wide)Str进行比较的信息。 - afrazier
1
这应该是真正正确的解决方案。正如我在其他解决方案中所述,生成语义等效的高级指令的更好代码取决于编译器,而不是程序员。程序员应始终优先考虑代码的可读性。 - Diego Queiroz

2

为了扩展@gabr的答案,如果我们修改源代码以添加额外的比较EmptyAnsiStr/EmptyWideStr/EmptyStr,我们会看到来自XE1的以下反汇编:

Project1.dpr.21: if sa3 = EmptyAnsiStr then
004111DD A1807E4100       mov eax,[$00417e80]
004111E2 8B15EC2C4100     mov edx,[$00412cec]
004111E8 8B12             mov edx,[edx]
004111EA E83148FFFF       call @LStrEqual

Project1.dpr.27: if sw3 = EmptyWideStr then
0041120D A18C7E4100       mov eax,[$00417e8c]
00411212 8B15E82C4100     mov edx,[$00412ce8]
00411218 8B12             mov edx,[edx]
0041121A E8CD49FFFF       call @WStrEqual

Project1.dpr.33: if su3 = EmptyStr then
00411236 A1987E4100       mov eax,[$00417e98]
0041123B 8B15BC2D4100     mov edx,[$00412dbc]
00411241 8B12             mov edx,[edx]
00411243 E8DC4CFFFF       call @UStrEqual

所有三个都需要函数调用。

同样的评论我可以在这里重复给 @gabr,汇编指令的数量在性能测试中并不意味着什么,因为某些指令比其他指令更快。在低级别上,生成语义等效的高级指令的更好代码是由编译器而非程序员来生成的。 - Diego Queiroz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接