如果与开关速度
由于编译器优化,switch语句通常比等效的if-else-if语句更快(如本文所描述的那样)。
这个优化如何实际工作? 有没有人有一个很好的解释?
编译器可以在适用的情况下构build跳转表。 例如,当您使用reflection器查看生成的代码时,您将看到对于string上的巨大开关,编译器将实际生成使用散列表来分派这些代码的代码。 散列表使用string作为关键字,并将其作为值委托给case
代码。
这比大量的链接if
testing有更好的运行时间,并且即使对于相对较less的string实际上也更快。
康拉德是正确的。 在切换连续的整数范围的情况下(例如,如果有情况0,情况1,情况2,情况n),编译器可以做得更好,因为它甚至不需要build立一个哈希表。 它只是存储一个函数指针数组,因此可以在一段时间内加载它的跳转目标。
这是一个小小的简化,因为通常任何现代编译器都遇到if..else if ..
序列,可以被一个人简单地转换成switch语句,编译器也是如此。 但是为了增加额外的乐趣,编译器不受语法的限制,因此可以在内部生成类似语句的“开关”,这些语句混合了范围,单个目标等等,而且它们可以(也可以)为switch和if这样做。 .else语句。
Anyhoo,Konrad的答案的一个扩展是编译器可以生成一个跳转表,但这不一定是保证的(也不是理想的)。 由于各种原因,跳转表对现代处理器上的分支预测器做坏事,并且表本身做坏事来caching行为,例如。
switch(a) { case 0: ...; break; case 1: ...; break; }
如果一个编译器实际上为此生成了一个跳转表,那么它可能会比较慢,因为跳转表会破坏分支预测,所以if..else if..
风格代码会更慢。
正如康拉德所说,编译器可以build立一个跳转表。
在C ++中,原因可能是由于交换机的限制。
- 比较项必须转换为int 。
- 案例labl必须是一个常数。
switch / case语句通常可以更快一级,但是当你开始进入2或更多时,开关/ case语句只要嵌套if / else语句就会开始2-3次。
这篇文章有一些速度比较,强调这些语句嵌套时的速度差异。
例如,根据他们的testing,示例代码如下所示:
if (x % 3 == 0) if (y % 3 == 0) total += 3; else if (y % 3 == 1) total += 2; else if (y % 3 == 2) total += 1; else total += 0; else if (x % 3 == 1) if (y % 3 == 0) total += 3; else if (y % 3 == 1) total += 2; else if (y % 3 == 2) total += 1; else total += 0; else if (x % 3 == 2) if (y % 3 == 0) total += 3; else if (y % 3 == 1) total += 2; else if (y % 3 == 2) total += 1; else total += 0; else if (y % 3 == 0) total += 3; else if (y % 3 == 1) total += 2; else if (y % 3 == 2) total += 1; else total += 0;
一半的时间完成等效的开关/ case语句运行:
switch (x % 3) { case 0: switch (y % 3) { case 0: total += 3; break; case 1: total += 2; break; case 2: total += 1; break; default: total += 0; break; } break; case 1: switch (y % 3) { case 0: total += 3; break; case 1: total += 2; break; case 2: total += 1; break; default: total += 0; break; } break; case 2: switch (y % 3) { case 0: total += 3; break; case 1: total += 2; break; case 2: total += 1; break; default: total += 0; break; } break; default: switch (y % 3) { case 0: total += 3; break; case 1: total += 2; break; case 2: total += 1; break; default: total += 0; break; } break; }
是的,这是一个简单的例子,但它说明了这一点。
因此,对于只有一个级别的简单types,可以使用switch / case,但是对于更复杂的比较和多个嵌套级别,使用经典的if / else结构呢?
不匹配的数据可能不好。
如果你真的下载源代码,那么在if和switch的情况下,不匹配的值就是21。 编译器应该能够抽象出来,知道应该随时运行哪个语句,并且CPU应该能够正确地进行分支预测。
更有意思的情况是,在我看来,并非每个案例都会被打破,但这可能不是实验的范围。
这是用C语言编写的PIC18单片机的代码:
void main() { int s1='0'; int d0; int d1; //if (s1 == '0') {d1 = '0'; d0 = '0';} //else if (s1 == '1') {d1 = '0';d0 = '1';} //else if (s1 == '2') {d1 = '1';d0 = '0';} //else if (s1 == '3') {d1 = '1';d0 = '1';} switch (s1) { case '0': {d1 = '0';d0 = '0';} break; case '1': {d1 = '0';d0 = '1';} break; case '2': {d1 = '1';d0 = '0';} break; case '3': {d1 = '1';d0 = '1';} break; } }
用ifs
s1='0' - 14 cycles s1='1' - 21 cycles s1='2' - 28 cycles s1='3' - 33 cycles s1='4' - 34 cycles
与案件
s1='0' - 17 cycles s2='1' - 23 cycles s3='2' - 29 cycles s4='3' - 35 cycles s5='4' - 32 cycles
所以我可以假设在非常低的水平ifs更快。 ROM中的代码也较短。