嗯,你应该考虑反汇编编译后的代码,看看实际生成了什么,但我希望在第二种情况下你最终得到的代码更少,分支也更少。
在第一种情况下,有七个赋值语句,还有一堆跳转(从switch语句中跳出来)。在第二个中,有一个数组引用和一个赋值。由于您的案例都是连续的,因此很容易处理默认案例:
value = ( input < 6 ) ? INPUT_TO_VALUE_TABLE[input] : default_value;
让我们看一些程序集。这是使用gcc -S 4.6.3 版本编译的,因此它与您得到的程序集不同,但我们应该得到相同的一般结果。这个答案不会绝对回答在你的情况下哪个会更好的问题;你必须自己做一些测试,但看起来很肯定这张桌子会更好。
switch 选项:
我们将从switch开始:
void switch_input( int input ) {
switch(input) {
case 0: value = VALUE_0;
break;
case 1: value = VALUE_1;
break;
case 2: value = VALUE_2;
break;
case 3: value = VALUE_3;
break;
case 4: value = VALUE_4;
break;
case 5: value = VALUE_5;
break;
case 6: value = VALUE_6;
break;
default: value = VALUE_DEFAULT;
break;
}
}
这里面有很多跳转,因为有七个不同的赋值,根据input的值,我们必须能够跳转到每一个,然后跳转到switch的末尾.
switch_input:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
cmpl $6, -4(%rbp)
ja .L2
movl -4(%rbp), %eax
movq .L10(,%rax,8), %rax
jmp *%rax
.section .rodata
.align 8
.align 4
.L10:
.quad .L3
.quad .L4
.quad .L5
.quad .L6
.quad .L7
.quad .L8
.quad .L9
.text
.L3:
movl $0, value(%rip)
jmp .L1
.L4:
movl $1, value(%rip)
jmp .L1
.L5:
movl $2, value(%rip)
jmp .L1
.L6:
movl $3, value(%rip)
jmp .L1
.L7:
movl $4, value(%rip)
jmp .L1
.L8:
movl $5, value(%rip)
jmp .L1
.L9:
movl $6, value(%rip)
jmp .L1
.L2:
movl $-1, value(%rip)
nop
.L1:
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
表格选项
table 选项可以只使用一个赋值,而不是有很多我们可以跳转到的代码,我们只需要一个值表。我们也不需要跳进那张桌子;我们只需要计算一个索引,然后无条件地从中加载一个值。
void index_input( int input ) {
value = ( input < N_VALUE ) ? INPUT_TO_VALUE_TABLE[input] : VALUE_DEFAULT;
}
(是的,我们确实应该在那里使用无符号整数,这样我们就知道它不会小于零。)
index_input:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
cmpl $5, -4(%rbp)
jg .L13
movl -4(%rbp), %eax
cltq
movl INPUT_TO_VALUE_TABLE(,%rax,4), %eax
jmp .L14
.L13:
movl $-1, %eax
.L14:
movl %eax, value(%rip)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
附录
C 代码(example.c)
int value;
#define N_VALUE 7
#define VALUE_0 0
#define VALUE_1 1
#define VALUE_2 2
#define VALUE_3 3
#define VALUE_4 4
#define VALUE_5 5
#define VALUE_6 6
#define VALUE_DEFAULT -1
void switch_input( int input ) {
switch(input) {
case 0: value = VALUE_0;
break;
case 1: value = VALUE_1;
break;
case 2: value = VALUE_2;
break;
case 3: value = VALUE_3;
break;
case 4: value = VALUE_4;
break;
case 5: value = VALUE_5;
break;
case 6: value = VALUE_6;
break;
default: value = VALUE_DEFAULT;
break;
}
}
const int INPUT_TO_VALUE_TABLE[N_VALUE] = {
VALUE_0,
VALUE_1,
VALUE_2,
VALUE_3,
VALUE_4,
VALUE_5,
VALUE_6
};
void index_input( int input ) {
value = ( input < 6 ) ? INPUT_TO_VALUE_TABLE[input] : VALUE_DEFAULT;
}
程序集(example.s)
由gcc -S生成。
.file "example.c"
.comm value,4,4
.text
.globl switch_input
.type switch_input, @function
switch_input:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
cmpl $6, -4(%rbp)
ja .L2
movl -4(%rbp), %eax
movq .L10(,%rax,8), %rax
jmp *%rax
.section .rodata
.align 8
.align 4
.L10:
.quad .L3
.quad .L4
.quad .L5
.quad .L6
.quad .L7
.quad .L8
.quad .L9
.text
.L3:
movl $0, value(%rip)
jmp .L1
.L4:
movl $1, value(%rip)
jmp .L1
.L5:
movl $2, value(%rip)
jmp .L1
.L6:
movl $3, value(%rip)
jmp .L1
.L7:
movl $4, value(%rip)
jmp .L1
.L8:
movl $5, value(%rip)
jmp .L1
.L9:
movl $6, value(%rip)
jmp .L1
.L2:
movl $-1, value(%rip)
nop
.L1:
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size switch_input, .-switch_input
.globl INPUT_TO_VALUE_TABLE
.section .rodata
.align 16
.type INPUT_TO_VALUE_TABLE, @object
.size INPUT_TO_VALUE_TABLE, 28
INPUT_TO_VALUE_TABLE:
.long 0
.long 1
.long 2
.long 3
.long 4
.long 5
.long 6
.text
.globl index_input
.type index_input, @function
index_input:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
cmpl $5, -4(%rbp)
jg .L13
movl -4(%rbp), %eax
cltq
movl INPUT_TO_VALUE_TABLE(,%rax,4), %eax
jmp .L14
.L13:
movl $-1, %eax
.L14:
movl %eax, value(%rip)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size index_input, .-index_input
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section .note.GNU-stack,"",@progbits