Для дальнейшего уточнения ответ Джерри и другие
Дано:
int x=1;
switch (i) {
case 1: x=6; break;
case 2: x++;
// Fall through
case 3: x+=7; break;
}
у вас может быть что-то вроде следующего:
int f1() {return 6;}
int f2() {return 1+f3();}
int f3() {return 8;}
Компилятор может использовать таблицу переходов для индексации {f1, f2, f3}
Компилятор может делать встраивание при создании таблицы, в которой f1, f2, f3
устанавливает x
непосредственно на 6,9,8
Но если вы написали функции и откатили свою собственную таблицу переходов, f1,f2,f3
может быть где угодно, но компилятор будет знать, чтобы поместить их близко к switch
, создавая гораздо лучшую локальность кода, чем вы могли бы.
Обратите внимание, что во многих случаях компилятор генерирует защиту для проверки, находится ли i
в диапазоне (или для обработки default
), и если вы уверены, что это всегда один из случаев, вы можете пропустить это
Интересно то, что для небольшого числа случаев и для разных флагов компилятора (в зависимости от компилятора) switch
не будет использовать таблицу, а будет просто делать if, аналогично:
if (i==1) x=f1();
else if (i==2) x=f2();
else if (i==3) x=f3();
или он может оптимизировать это (где простые тесты являются одной инструкцией) для:
x=(i==1) ? f1()
: (i==2) ? f2()
: (i==3) ? f3()
: x;
Лучший совет - взглянуть на сгенерированную сборку, чтобы увидеть, что компилятор сделал с вашим кодом в вашей архитектуре. G ++ в Linux / intel сгенерирует что-то вроде следующего, если есть таблица переходов
( примечание: мне нужно было перейти к 5 case
операторам, чтобы вызвать таблицу переходов, она использовала, если значение меньше 10 * * операторов )
Обратите внимание, что в таблице переходов будут маленькие отверстия для выполнения default
int foo(int i)
{
int x=1;
switch (i) {
case 1: x=6; break;
case 2: x++;
// Fall through
case 3: x+=7; break;
case 4: x+=2; break;
case 5: x+=9; break;
}
return x;
}
сгенерирует следующий код сборки ( // комментарии мои ):
cmp edi, 5 //make sure it is not over 5
ja .L2 //jump to default case
mov edi, edi
jmp [QWORD PTR .L4[0+rdi*8]] // use the jump table at label L4:
.L4:
.quad .L2 // if i=0, set x=1 (default)
.quad .L9 // f1() see below
.quad .L10 // f2() see below
.quad .L6 // f3() see below
.quad .L7 // f4() see below
.quad .L8 // f5() see below
.L10:
mov eax, 9 // x=9
ret
.L9:
mov eax, 6 // x=6
ret
.L8:
mov eax, 10 // x=10
ret
.L6:
mov eax, 8 // x=8
ret
.L7:
mov eax, 3 // x=3
ret
.L2:
mov eax, 1 // default, x was 1, noop is: x=1
ret