gpt4 book ai didi

c - switch 还是 const table 更好? (嵌入式软件)

转载 作者:太空狗 更新时间:2023-10-29 15:19:51 24 4
gpt4 key购买 nike

我想知道,在可能的情况下,switch 还是 const table 更有效?

例如,什么会表现更好:

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:
break;
}

或者像这样:

const uint8_t INPUT_TO_VALUE_TABLE[N_VALUE] = {
VALUE_0,
VALUE_1,
VALUE_2,
VALUE_3,
VALUE_4,
VALUE_5,
VALUE_6,
}
...
...
value = INPUT_TO_VALUE_TABLE[input];

我展示了一个虚拟示例,但我还有使用开关调用不同函数或函数指针表的代码。

该代码适用于 8 位微型计算机(我不知道它是否对本主题有任何影响)。

最佳答案

好吧,您应该考虑反汇编编译后的代码以查看实际生成的内容,但我希望在第二种情况下您最终得到的代码更少,并且分支也更少。

在第一种情况下,有七个赋值语句,以及一堆跳转(switch 语句之外)。第二个是一个数组引用和一个赋值。由于您的案例都是连续的,因此很容易处理默认案例:

value = ( input < 6 ) ? INPUT_TO_VALUE_TABLE[input] : default_value;

让我们看一些汇编。这是用 gcc -S 版本 4.6.3 编译的,因此它与您得到的程序集不同,但我们应该得到相同的一般结果。这个答案不会绝对回答哪个对你的情况更好的问题;您必须自己做一些测试,但看起来很确定该表会更可取。

开关选项:

我们将从开关开始:

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_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

关于c - switch 还是 const table 更好? (嵌入式软件),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21603336/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com