Теоретически, для полного коммутатора компилятор будет генерировать таблицу перехода, то есть массив указателей на метки, в которые нужно индексировать напрямую (при условии, что значение соответствует диапазону).
Для менее полной версии компилятор должен балансировать таблицу перехода и инструкции ветвления. Вероятно, это будет зависеть и от настроек: увеличьте ли вы максимальную скорость с -O3
или минимизируйте размер с помощью -Oz
, чтобы повлиять на некоторые кромки.
Наконец, коммутатор имеет только один корпус, он, скорее всего, будет представлен как ветка.
Наличие break
или провал не сильно влияет на ситуацию. Сборка определяется в терминах меток, и как break
, так и пассаж естественно представлены, поэтому не должны влиять на использование ветвей или таблиц прыжков.
Demo (с использованием Попробуйте сайт LLVM)
enum Enum {
Zero,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine
};
char const* full(enum Enum e) {
switch(e) {
case Zero: return "Zero";
case One: return "One";
case Two: return "Two";
case Three: return "Three";
case Four: return "Four";
case Five: return "Five";
case Six: return "Six";
case Seven: return "Seven";
case Eight: return "Eight";
case Nine: return "Nine";
}
return "Uh ?";
}
char const* sparse(enum Enum e) {
switch(e) {
default: return "Not handled";
case Zero: return "Zero";
case One: return "One";
case Two: return "Two";
case Seven: return "Seven";
case Eight: return "Eight";
case Nine: return "Nine";
}
}
char const* null(enum Enum e) {
switch(e) {
default: return "Not Zero";
case Zero: return "Zero";
}
}
Функция full
компилируется:
.text
.globl full
.align 16, 0x90
.type full,@function
full: # @full
.Ltmp0:
.cfi_startproc
# BB#0:
cmpl $9, %edi
ja .LBB0_11
# BB#1:
movl %edi, %ecx
movl $.L.str, %eax
jmpq *.LJTI0_0(,%rcx,8)
.LBB0_2:
movl $.L.str1, %eax
ret
.LBB0_3:
movl $.L.str2, %eax
ret
.LBB0_4:
movl $.L.str3, %eax
ret
.LBB0_5:
movl $.L.str4, %eax
ret
.LBB0_6:
movl $.L.str5, %eax
ret
.LBB0_7:
movl $.L.str6, %eax
ret
.LBB0_8:
movl $.L.str7, %eax
ret
.LBB0_9:
movl $.L.str8, %eax
ret
.LBB0_10:
movl $.L.str9, %eax
ret
.LBB0_11:
movl $.L.str10, %eax
.LBB0_12:
ret
.Ltmp1:
.size full, .Ltmp1-full
.Ltmp2:
.cfi_endproc
.Leh_func_end0:
.section .rodata,"a",@progbits
.align 8
.LJTI0_0:
.quad .LBB0_12
.quad .LBB0_2
.quad .LBB0_3
.quad .LBB0_4
.quad .LBB0_5
.quad .LBB0_6
.quad .LBB0_7
.quad .LBB0_8
.quad .LBB0_9
.quad .LBB0_10
И функция sparse
к:
.text
.globl sparse
.align 16, 0x90
.type sparse,@function
sparse: # @sparse
.Ltmp3:
.cfi_startproc
# BB#0:
movl $.L.str11, %eax
cmpl $9, %edi
ja .LBB1_8
# BB#1:
movl %edi, %ecx
jmpq *.LJTI1_0(,%rcx,8)
.LBB1_2:
movl $.L.str, %eax
ret
.LBB1_3:
movl $.L.str1, %eax
ret
.LBB1_4:
movl $.L.str2, %eax
ret
.LBB1_5:
movl $.L.str7, %eax
ret
.LBB1_6:
movl $.L.str8, %eax
ret
.LBB1_7:
movl $.L.str9, %eax
.LBB1_8:
ret
.Ltmp4:
.size sparse, .Ltmp4-sparse
.Ltmp5:
.cfi_endproc
.Leh_func_end1:
.section .rodata,"a",@progbits
.align 8
.LJTI1_0:
.quad .LBB1_2
.quad .LBB1_3
.quad .LBB1_4
.quad .LBB1_8
.quad .LBB1_8
.quad .LBB1_8
.quad .LBB1_8
.quad .LBB1_5
.quad .LBB1_6
.quad .LBB1_7
A nd, наконец, функция null
:
.text
.globl null
.align 16, 0x90
.type null,@function
null: # @null
.Ltmp0:
.cfi_startproc
# BB#0:
movl $.L.str1, %ecx
testl %edi, %edi
movl $.L.str, %eax
cmoveq %rcx, %rax
ret
.Ltmp1:
.size null, .Ltmp1-null
.Ltmp2:
.cfi_endproc
.Leh_func_end0:
У вас есть 'break' на каждом' случае'? Если нет, то это может изменить ситуацию, если да, я не могу представить компилятор, который не может его оптимизировать, и создает менее оптимальный код для сценария 2, основанный только на порядке меток 'case'. – vsz
До тех пор, пока код логически эквивалентен, бизнес компилятора относится к тому, как он закладывает вещи. Спросите своего компилятора (т. Е. Проверьте его и посмотрите на результат). – Mat
Попробуйте, это не займет много времени, чтобы написать тест для этого. Я подозреваю, что это не имеет значения, если синтаксис правильный. Как и vsz, компилятор будет оптимизировать результат, если вы используете параметр/o. –