Far*_*d A 3 c++ compilation switch-statement
从我从类似问题的各种答案中读到的内容,在某些情况下,切换案例的编译方式也不同.
我有几个场景,但我不确定它们将如何编译.
采用枚举值的开关盒.案件范围从0到99并且是有序的.
采用枚举值的开关盒.这些案件的范围从0 - 30,50 - 80,100 - 150.无序.这个编译会不同于上面的场景?
基本上我想知道如何编译场景中的切换案例,以及两个场景之间是否存在任何差异.谢谢!
编辑:我应该提到我最关心的一个问题是需要多少支票才能匹配案例.如果语句是线性的,那么对于方案一,如果它是if-else-如果它最多需要100次检查,除非我弄错了.但这如何处理开关盒?编译器做了什么样的优化?
一般来说,没有办法说出来.C++标准几乎没有对生成的代码做任何假设.这意味着只要语义保持不变,编译器几乎可以自由地(是的,有例外)重新排序代码.当我参加该主题的课程时,优化通常被称为"编译器构造的黑魔法".
考虑到这一点,您的编译器可能会喷出相同或不同的代码.对于某些优化级别,它可能会吐出相同的代码,而对于其他优化级别则可能会完全不同 它可能完全取决于您在case块本身中使用的代码.如果你在两点有相同的代码,它可能只是优化它以使用该代码一次,或者它可能不会.
知道将会发生什么的唯一方法是查看具有某些固定标志的编译器的输出,看看会发生什么.一旦你发现了会发生什么,不要依赖它,它可能会在下一版本的编译器中发生变化.
如果您正在编程,请始终遵守语言标准为您提供的保证,并且永远不要假设任何其他内容.
从理论上讲,对于完全切换,编译器将生成一个跳转表,即,一个指向标签的指针数组,该标签可在其中直接建立索引(前提是该值适合范围)。
对于较不完整的版本,由编译器来平衡跳转表和分支语句。这也可能取决于设置:使用最大化速度-O3或最小化尺寸-Oz肯定会影响某些边缘情况。
最后,该开关只有一种情况,它可能会被表示为分支。
存在break或失败不会对事物产生太大影响。汇编是根据标签定义的,并且breakfallthrough和fallthrough是自然表示的,因此它不应影响使用分支还是跳转表。
演示(使用试用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";
}
}
Run Code Online (Sandbox Code Playgroud)
函数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
Run Code Online (Sandbox Code Playgroud)
和功能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
Run Code Online (Sandbox Code Playgroud)
最后是功能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:
Run Code Online (Sandbox Code Playgroud)