一个好的编译器可以并且将会在跳转表、链式 if/else 或组合之间进行选择。设计不佳的编译器可能不会做出这样的选择——甚至可能会为开关块生成非常糟糕的代码。但是任何体面的编译器都应该为开关块生成有效的代码。吨
这里的主要决定因素是编译器可以选择 if/else 当数字相距很远[而不是微不足道(例如除以 2、4、8、16、256 等)更改为更接近的值],例如
switch(x)
{
case 1:
...
case 4912:
...
case 11211:
...
case 19102:
...
}
需要一个至少 19102 * 2 字节的跳转表。
另一方面,如果数字很接近,编译器通常会使用跳转表。
即使它是一种if/else
设计,它通常也会进行“二分查找”——如果我们采用上面的示例:
if (x <= 4912)
{
if (x == 1)
{
....
}
else if (x == 4912)
{
....
}
} else {
if (x == 11211)
{
....
}
else if (x == 19102)
{
...
}
}
如果我们有很多案例,这种方法会嵌套很深,并且人类可能会在三到四个深度级别后迷路(请记住,每个 if 都从范围中间的某个点开始),但它减少了log2(n) 的测试次数,其中 n 是选择的数量。它肯定比天真的方法更有效
if (x == first value) ...
else if (x == second value) ...
else if (x == third value) ...
..
else if (x == nth value) ...
else ...
如果将某些值放在 if-else 链的开头,这可能会稍微好一些,但前提是您可以在运行代码之前确定最常见的值。
如果性能对您的情况至关重要,那么您需要对这两种选择进行基准测试。但我的猜测是,仅将代码编写为开关将使代码更清晰,同时运行速度至少一样快,如果不是更快的话。