delphi 在except块中额外的分号,有什么用途?可选的分号在except或end之前,有或没有更好?

b1uwtaje  于 2022-11-23  发布在  其他
关注(0)|答案(4)|浏览(153)

在 Delphi 10.3.3应用程序中工作,有大量的额外和缺失的分号。如果在任何块结束语句之前删除分号,则应用程序将编译。
在代码中,[except]和[end]之间的浮点分号是否有任何用途,例如加快运行速度或抛出某个默认异常,或者有其他用途?
这会引发随机编译或运行时错误吗?
在end或except之前的最后一行中保留分号是否会加快运行时速度?
一种方法是否比另一种方法更容易出错,或者是否容易出现随机编译或运行时错误?
下面的代码可以拖放到任何测试项目中,该项目的窗体具有一个编辑框、一个按钮和一个用拖放默认设置创建的备忘录框。

function TForm1.isThisUseful(this : string): boolean;
var
  i: Integer;
begin
  result := false;
  try
    if this = ''
    then
      i := 0
    else
      i := 1
  except
    ;
  end;
  result := (i > 0)
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if isThisUseful(Edit1.Text)
  then
    Memo1.Text := 'Yes, it is useful'
  else
    Memo1.Text := 'This is a waste of time.'
end;
dluptydi

dluptydi1#

tl;dr:没有任何区别。

try
  // do stuff
except
  ;
end;

这个分号可以被删除。它绝对没有任何作用。它没有好处,也没有坏处(除了,可能,它使源代码看起来很奇怪,这是你应该避免的1)。

begin
  DoThis;
  DoThat;
end;

因为在 Delphi 中,分号 * 分隔 * 语句,所以end前面的最后一个分号是不必要的。它绝对没有任何作用。它主要是一个品味的问题,如果你想要它或不(就我个人而言,有时有,有时没有)。
使用分号的一个好处是,你可以将这一行移动或复制到其他地方,而不必修改它。同样,你也可以在这一行代码后面插入一个新的语句,而不需要添加分号。恕我直言,这些都是非常小的好处;在必要时添加分号并不困难。

  • 附言:* 不过,result := (i > 0)对我来说确实很奇怪。我希望是Result := i > 0,没有不必要的括号。(这可能是因为我几乎每天都用 Delphi 编程,已经超过20年了。)
  • 额外注解2:* 请注意,编译器很乐意接受
begin
  DoThis;;
  DoThat;
end;

它只是忽略了多余的分号。但是上面的代码片段在我看来 * 非常 * 难看,而且我总是觉得很奇怪,开发人员选择提交代码而不先阅读它。

  • 附言3:* Ken Bourassa写了一个answer,给出了一个例子,在这个例子中,分号的存在与否 * 确实 * 会影响程序。但是还有一个更可怕的例子:
case i of
  0:
    DoA;
  1:
    DoB;
  2:
    if j = 0 then
      DoC{;}
else
  DoD;
end;

1在这种情况下,你也可以说分号是有用途的:它“突出显示”了空的except块,使其更容易被快速发现。因此,它可能是有意的。但有人可能会争辩说,突出显示它的更好方法是包含一个像// Do nothing// Just carry on这样的注解。(而且,在许多情况下,如果不是大多数情况下,空的except块一点也不好。)

roejwanj

roejwanj2#

我想我会尝试一些测量,在这个D7测试程序上使用NexusDB's Quality Suite的线路定时器:

{$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 semicolontest;

{$APPTYPE CONSOLE}

uses
  SysUtils;

function isThisUseful1(this : string): boolean;
var
  i: Integer;
begin
  result := false;
  try
    if this = ''
    then
      i := 0
    else
      i := 1
  except
    ;
  end;
  result := (i > 0)
end;

function isThisUseful2(this : string): boolean;
var
  i: Integer;
begin
  result := false;
  try
    if this = ''
    then
      i := 0
    else
      i := 1
  except

  end;
  result := (i > 0)
end;

var
  Input : String[20];
  i : Integer;
  Res : Boolean;

begin

   Input := 'abcdefg';

   writeln('Starting');
   for i := 1 to 1000000 do begin
     Res := isThisUseful1(Input);
     Res := isThisUseful2(Input);
   end;
   writeln('Done');
   // readln;
end.

其中包含问题中isThisUseful函数的两个版本,一个在except块中带有分号,另一个不带分号。运行此代码的结果(抱歉,布局有点混乱)如下所示:

Line    Total Time  Hit Count   Source
1       -   {$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}
2       -   program semicolontest;
3       -   
4       -   {$APPTYPE CONSOLE}
5       -   
6       -   uses
7       -     SysUtils;
8       -   
9       -   function isThisUseful1(this : string): boolean;
10      -   var
11      -     i: Integer;
12  2.807175    1,000,000   begin
13  0.761388    1,000,000     result := false;
14  2.133202    1,000,000     try
15  1.403061    1,000,000       if this = ''
16      -       then
17      -         i := 0
18      -       else
19  0.826841    1,000,000         i := 1
20      -     except
21      -       ;
22      -     end;
23  0.735419    1,000,000     result := (i > 0)
24      -   end;
25      -   
26      -   function isThisUseful2(this : string): boolean;
27      -   var
28      -     i: Integer;
29  1.260030    1,000,000   begin
30  0.782293    1,000,000     result := false;
31  0.894420    1,000,000     try
32  0.820860    1,000,000       if this = ''
33      -       then
34      -         i := 0
35      -       else
36  0.873424    1,000,000         i := 1
37      -     except
38      -   
39      -     end;
40  0.778922    1,000,000     result := (i > 0)
41      -   end;
42      -   
43      -   var
44      -     Input : String[20];
45      -     i : Integer;
46      -     Res : Boolean;
47      -   
48  1.167140    1   begin
49      -   
50  0.000036    1      Input := 'abcdefg';
51      -   
52  0.641347    1      writeln('Starting');
53  0.000026    1      for i := 1 to 1000000 do begin
54      -        Res := isThisUseful1(Input);
55      -        Res := isThisUseful2(Input);
56  0.669066    1,000,000      end;
57  0.402661    1      writeln('Done');
58      -      // readln;
59      -   end.
60      -

请注意,第21行(try ...except块中的分号)没有记录时间,原因很简单,正如预期的那样,没有为它生成代码。
为了完整起见,以下是isThisUseful1isThisUseful2的反汇编
这是否有用1:

Address Bytes   Text    Block #
00408620h       [semicolontest.dpr.12] begin    
00408620h   55        push ebp  1
00408621h   8BEC          mov ebp, esp  1
00408623h   83C4F4        add esp, 0FFFFFFF4h ; (-0Ch)  1
00408626h   53        push ebx  1
00408627h   56        push esi  1
00408628h   57        push edi  1
00408629h   8945FC        mov [ebp-04h], eax    1
0040862Ch   8B45FC        mov eax, [ebp-04h]    1
0040862Fh   E87CB7FFFF        call System::LStrAddRef ;(00403DB0h)  1
00408634h   33C0          xor eax, eax  1
00408636h   55        push ebp  1
00408637h   689A864000        push offset @@6   1
0040863Ch   64FF30        push fs:[eax] 1
0040863Fh   648920        mov fs:[eax], esp 1
00408642h       [semicolontest.dpr.13] result := false; 
00408642h   C645FB00          mov byte ptr [ebp-05h], 00h   1
00408646h       [semicolontest.dpr.14] try  
00408646h   33C0          xor eax, eax  1
00408648h   55        push ebp  1
00408649h   6872864000        push offset @@3   1
0040864Eh   64FF30        push fs:[eax] 1
00408651h   648920        mov fs:[eax], esp 1
00408654h       [semicolontest.dpr.15] if this = '' 
00408654h   837DFC00          cmp dword ptr [ebp-04h], 00h  1
00408658h   7507          jnz @@1   1
0040865Ah       [semicolontest.dpr.17] i := 0   
0040865Ah   33C0          xor eax, eax  2
0040865Ch   8945F4        mov [ebp-0Ch], eax    2
0040865Fh   EB07          jmp @@2   2
00408661h       [semicolontest.dpr.19] i := 1   
00408661h       @@1:    
00408661h   C745F401000000        mov dword ptr [ebp-0Ch], 01h  3
00408668h       @@2:    
00408668h   33C0          xor eax, eax  4
0040866Ah   5A        pop edx   4
0040866Bh   59        pop ecx   4
0040866Ch   59        pop ecx   4
0040866Dh   648910        mov fs:[eax], edx 4
00408670h   EB0A          jmp @@4   4
00408672h       @@3:    
00408672h   E9DDACFFFF        jmp System::HandleAnyException ;(00403354h)   5
00408677h       [semicolontest.dpr.21] ;    
00408677h   E8B8AEFFFF        call System::DoneExcept ;(00403534h)  5
0040867Ch       [semicolontest.dpr.23] result := (i > 0)    
0040867Ch       @@4:    
0040867Ch   837DF400          cmp dword ptr [ebp-0Ch], 00h  6
00408680h   0F9F45FB          setnle [ebp-05h]  6
00408684h   33C0          xor eax, eax  6
00408686h   5A        pop edx   6
00408687h   59        pop ecx   6
00408688h   59        pop ecx   6
00408689h   648910        mov fs:[eax], edx 6
0040868Ch   68A1864000        push offset @@7   6
00408691h       @@5:    
00408691h   8D45FC        lea eax, [ebp-04h]    7
00408694h   E8BFB3FFFF        call System::LStrClr ;(00403A58h) 7
00408699h   C3        ret   7
0040869Ah       @@6:    
0040869Ah   E9E1ADFFFF        jmp System::HandleFinally ;(00403480h)    8
0040869Fh   EBF0          jmp @@5   8
004086A1h       @@7:    
004086A1h   8A45FB        mov al, [ebp-05h] 9
004086A4h       [semicolontest.dpr.24] end; 
004086A4h   5F        pop edi   9
004086A5h   5E        pop esi   9
004086A6h   5B        pop ebx   9
004086A7h   8BE5          mov esp, ebp  9
004086A9h   5D        pop ebp   9
004086AAh   C3        ret   9

这是否有用2:

Address Bytes   Text    Block #
00408620h       [semicolontest.dpr.12] begin    
00408620h   55        push ebp  1
00408621h   8BEC          mov ebp, esp  1
00408623h   83C4F4        add esp, 0FFFFFFF4h ; (-0Ch)  1
00408626h   53        push ebx  1
00408627h   56        push esi  1
00408628h   57        push edi  1
00408629h   8945FC        mov [ebp-04h], eax    1
0040862Ch   8B45FC        mov eax, [ebp-04h]    1
0040862Fh   E87CB7FFFF        call System::LStrAddRef ;(00403DB0h)  1
00408634h   33C0          xor eax, eax  1
00408636h   55        push ebp  1
00408637h   689A864000        push offset @@6   1
0040863Ch   64FF30        push fs:[eax] 1
0040863Fh   648920        mov fs:[eax], esp 1
00408642h       [semicolontest.dpr.13] result := false; 
00408642h   C645FB00          mov byte ptr [ebp-05h], 00h   1
00408646h       [semicolontest.dpr.14] try  
00408646h   33C0          xor eax, eax  1
00408648h   55        push ebp  1
00408649h   6872864000        push offset @@3   1
0040864Eh   64FF30        push fs:[eax] 1
00408651h   648920        mov fs:[eax], esp 1
00408654h       [semicolontest.dpr.15] if this = '' 
00408654h   837DFC00          cmp dword ptr [ebp-04h], 00h  1
00408658h   7507          jnz @@1   1
0040865Ah       [semicolontest.dpr.17] i := 0   
0040865Ah   33C0          xor eax, eax  2
0040865Ch   8945F4        mov [ebp-0Ch], eax    2
0040865Fh   EB07          jmp @@2   2
00408661h       [semicolontest.dpr.19] i := 1   
00408661h       @@1:    
00408661h   C745F401000000        mov dword ptr [ebp-0Ch], 01h  3
00408668h       @@2:    
00408668h   33C0          xor eax, eax  4
0040866Ah   5A        pop edx   4
0040866Bh   59        pop ecx   4
0040866Ch   59        pop ecx   4
0040866Dh   648910        mov fs:[eax], edx 4
00408670h   EB0A          jmp @@4   4
00408672h       @@3:    
00408672h   E9DDACFFFF        jmp System::HandleAnyException ;(00403354h)   5
00408677h       [semicolontest.dpr.21] ;    
00408677h   E8B8AEFFFF        call System::DoneExcept ;(00403534h)  5
0040867Ch       [semicolontest.dpr.23] result := (i > 0)    
0040867Ch       @@4:    
0040867Ch   837DF400          cmp dword ptr [ebp-0Ch], 00h  6
00408680h   0F9F45FB          setnle [ebp-05h]  6
00408684h   33C0          xor eax, eax  6
00408686h   5A        pop edx   6
00408687h   59        pop ecx   6
00408688h   59        pop ecx   6
00408689h   648910        mov fs:[eax], edx 6
0040868Ch   68A1864000        push offset @@7   6
00408691h       @@5:    
00408691h   8D45FC        lea eax, [ebp-04h]    7
00408694h   E8BFB3FFFF        call System::LStrClr ;(00403A58h) 7
00408699h   C3        ret   7
0040869Ah       @@6:    
0040869Ah   E9E1ADFFFF        jmp System::HandleFinally ;(00403480h)    8
0040869Fh   EBF0          jmp @@5   8
004086A1h       @@7:    
004086A1h   8A45FB        mov al, [ebp-05h] 9
004086A4h       [semicolontest.dpr.24] end; 
004086A4h   5F        pop edi   9
004086A5h   5E        pop esi   9
004086A6h   5B        pop ebx   9
004086A7h   8BE5          mov esp, ebp  9
004086A9h   5D        pop ebp   9
004086AAh   C3        ret   9

(我自己也在试图比较这些数据,我不想浪费时间在BeyondCompare上运行它们)。
无论如何,我认为这表明,正如我和其他人所说的,编译器不会为try...except块中只包含分号的行生成代码,也不应该在其他任何地方生成代码,尽管正如所指出的,存在或不存在分号会改变代码的语义,从而改变生成的代码。

oknwwptz

oknwwptz3#

除了安德烈亚斯的回答......
有一种情况,你肯定(或者,至少,最有可能)不想在“then”后面留下分号。下面的代码将在消息框中显示“B”。

procedure TForm3.FormCreate(Sender: TObject);
var
  S : String;
begin
  S := 'A';
  if 1 = 2 then;
    S := 'B';

  ShowMessage(S);
end;

在我看来,这是唯一一种插入分号会自行更改代码代的情况。

sr4lhrrt

sr4lhrrt4#

感谢大家对这篇文章的反馈。我想总结一下几点。
分号改变了应用程序编译的方式。因此,应用程序的大小可以改变很小的量。所以,它看起来像是应用程序中的硬终止符或分支切换终止符。也就是说,它可能应该在每个Try的末尾,除了end;在每个except或finally之前,以及在每个循环的末尾,无论后面的内容如何,都要确保编译干净且一致。
但不应该是另一个[end]语句之前的if-[end]语句中缺少的一个问题,或者是在没有其他代码存在的地方作为一个附加项。但可能在循环中多加一个分号,这不是最好的主意。

相关问题