楼上和楼上的楼上和楼上的楼上的楼上 的理解能力有问题还是我表达能力不咋滴啊 我的意思是 Case 编译出来的机器码 比 If 编译的速度快吗?
具体要看情况,如果是简单的case语句,确实比if稍稍快一些,比如:case x of 0: y := 1; 1: y := 2; 2: y := 3; end;case汇编代码大概是: mov eax, x sub eax, 1 jb @@end // 小于0退出 jz @@1 // 0 dec eax jz @@2 // 1 jmp @@3 // 2 @@1: mov eax, 1 jmp @@4 @@2: mov eax, 2 jmp @@4 @@3: mov eax, 3 @@4: mov y, eax @@end:如果用if语句,汇编码大概是: mov eax, x test eax, eax jnz @@1 mov eax, 1 jmp @@3 @@1: cmp eax, 1 jne @@2 mov eax, 2 jmp @@3 @@2: cmp eax, 2 jne @@end mov eax, 3 @@3: mov y, eax @@end: 随手写的,不见得正确
翻一下历史贴子吧,其中对这个问题的说明已经足够多了。要去说明这个问题,需要把代码展开成为汇编指令才能够直观地表达出来。简单地说Delphi的CASE表达式,由于语法上的限制,而强制采用了常量比较,因此对于多分支的CASE表达式,则只需要一次计算,但是化作为if就有可能因为语法习惯性,导致多次运算。这些都是理论上的,需要根据具体的情况而定,比如if条件表达式只是一个单一条件表达式,那么编译器实际本身主可以通过优化机制做到最优。function Test(b: Boolean;a: Integer): integer; begin if b and (a=1) then begin result := 10; end else if b and (a=2) then begin result := 100; end else begin result := 1000; end; end;类似上面这样的代码,很明显第二个条件表示式当中的 b(=true)这个条件是可以与第一个条件合并掉的。如果你使用case表达式的话,则肯定会避免这样的问题,代码将会变成: function Test(b: Boolean;a: Integer): integer; begin Result := 1000; if Not b then Exit; case a of 1:result := 10; 2:result := 100; end; end; 对于这样一段代码,所带来的效果,其实不尽其然,基本上可以忽略。但是如果是下面这样的代码,或许就会是非常有效的改善: function Test(b: Boolean;a: string): integer; begin if b and (a='1') then begin result := 10; end else if b and (a='2') then begin result := 100; end else begin result := 1000; end; end;比如优化一: function Test(b: Boolean;a: string): integer; begin Result := 1000; if Not b then Exit; case StrToIntDef(a,-1) of 1: Result := 10; 2: Result := 100; end; end; 比如优化二: function Test(b: Boolean;a: string): integer; begin Result := 1000; if Not b then Exit; if Length(a) <> 1 then Exit; case PAnsiChar(a)^ of '1': Result := 10; '2': Result := 100; end; end;当然这只是两个分支,并没有多少的意义。写代码本身也是仁者见仁智者见智的事情,每个程序或者设计者都会依据实际需要,权衡利弊做出不同的处理,比如说下面这段代码: function Test(b: Boolean;a: string): integer; begin if b and (a='abcd') then begin result := 10; end else if b and (a='xyz0') then begin result := 100; end else begin result := 1000; end; end; 或者可以优化成: function Test(b: Boolean;a: string): integer; begin Result := 1000; if Not b then Exit; if Length(a) <> 4 then Exit; case PAnsiChar(a)^ of $64636261 (*'abcd'*): Result := 10; $307a7978 (*'xyz0'*): Result := 100; end; end;在这个优化当中,只是假定了a的值有且只四个字符为必要分支条件的前提,如果再来些一个字符、两个字符,或许还稍好办一点,但要是三个呢?五个呢?处理起来就有可能有点不伦不类,至少增加了阅读的难度,或者需要修改原有的代码风格。代码优化始终是一个无止境的话题,优化除了性能优化,同时还有(目标代码)存储优化,甚至是执行需求优化等等,这几者之间甚或还有可能是一个个相互矛盾的关系,如何取舍对于设计者就有相当的考验。
我的意思是
Case 编译出来的机器码 比 If 编译的速度快吗?
0: y := 1;
1: y := 2;
2: y := 3;
end;case汇编代码大概是: mov eax, x
sub eax, 1
jb @@end // 小于0退出
jz @@1 // 0
dec eax
jz @@2 // 1
jmp @@3 // 2
@@1:
mov eax, 1
jmp @@4
@@2:
mov eax, 2
jmp @@4
@@3:
mov eax, 3
@@4:
mov y, eax
@@end:如果用if语句,汇编码大概是:
mov eax, x
test eax, eax
jnz @@1
mov eax, 1
jmp @@3
@@1:
cmp eax, 1
jne @@2
mov eax, 2
jmp @@3
@@2:
cmp eax, 2
jne @@end
mov eax, 3
@@3:
mov y, eax
@@end:
随手写的,不见得正确
begin
if b and (a=1) then begin
result := 10;
end else if b and (a=2) then begin
result := 100;
end else begin
result := 1000;
end;
end;类似上面这样的代码,很明显第二个条件表示式当中的 b(=true)这个条件是可以与第一个条件合并掉的。如果你使用case表达式的话,则肯定会避免这样的问题,代码将会变成:
function Test(b: Boolean;a: Integer): integer;
begin
Result := 1000;
if Not b then Exit;
case a of
1:result := 10;
2:result := 100;
end;
end;
对于这样一段代码,所带来的效果,其实不尽其然,基本上可以忽略。但是如果是下面这样的代码,或许就会是非常有效的改善:
function Test(b: Boolean;a: string): integer;
begin
if b and (a='1') then begin
result := 10;
end else if b and (a='2') then begin
result := 100;
end else begin
result := 1000;
end;
end;比如优化一:
function Test(b: Boolean;a: string): integer;
begin
Result := 1000;
if Not b then Exit;
case StrToIntDef(a,-1) of
1: Result := 10;
2: Result := 100;
end;
end;
比如优化二:
function Test(b: Boolean;a: string): integer;
begin
Result := 1000;
if Not b then Exit;
if Length(a) <> 1 then Exit; case PAnsiChar(a)^ of
'1': Result := 10;
'2': Result := 100;
end;
end;当然这只是两个分支,并没有多少的意义。写代码本身也是仁者见仁智者见智的事情,每个程序或者设计者都会依据实际需要,权衡利弊做出不同的处理,比如说下面这段代码:
function Test(b: Boolean;a: string): integer;
begin
if b and (a='abcd') then begin
result := 10;
end else if b and (a='xyz0') then begin
result := 100;
end else begin
result := 1000;
end;
end;
或者可以优化成:
function Test(b: Boolean;a: string): integer;
begin
Result := 1000;
if Not b then Exit;
if Length(a) <> 4 then Exit; case PAnsiChar(a)^ of
$64636261 (*'abcd'*): Result := 10;
$307a7978 (*'xyz0'*): Result := 100;
end;
end;在这个优化当中,只是假定了a的值有且只四个字符为必要分支条件的前提,如果再来些一个字符、两个字符,或许还稍好办一点,但要是三个呢?五个呢?处理起来就有可能有点不伦不类,至少增加了阅读的难度,或者需要修改原有的代码风格。代码优化始终是一个无止境的话题,优化除了性能优化,同时还有(目标代码)存储优化,甚至是执行需求优化等等,这几者之间甚或还有可能是一个个相互矛盾的关系,如何取舍对于设计者就有相当的考验。