稀疏值(sparse)的switch-case语句,编译器生成了条件跳转链(if-else链)的实现方式
文章目录
- 完整代码
- 汇编部分
- 汇编特征分析
- 1. 初始比较和分支
- 2. 大于100的分支处理
- 3. 各case块执行
- 关键特征总结
- 对应的C++代码推测
完整代码
#include <string>// 基础输出模拟
void output(int val) {static int buffer;buffer = val;
}// 1. 密集连续值 - 可能生成跳转表
void switch_dense_sequential(int value) {switch (value) {case 1: output(100); break;case 2: output(200); break;case 3: output(300); break;case 4: output(400); break;case 5: output(500); break;case 6: output(100); break;case 7: output(200); break;case 8: output(300); break;case 9: output(400); break;case 10: output(500); break;default: output(0); break;}
}// 2. 稀疏值 - 可能生成条件跳转链
void switch_sparse(int value) {switch (value) {case 10: output(1000); break;case 50: output(5000); break;case 100: output(10000); break;case 500: output(50000); break;default: output(0); break;}
}// 3. 有小间隔的值 - 可能使用小表优化
void switch_small_gaps(int value) {switch (value) {case 1: output(10); break;case 3: output(30); break;case 5: output(50); break;case 7: output(70); break;case 9: output(90); break;default: output(0); break;}
}// 4. 带fall-through的case
void switch_fallthrough(int value) {switch (value) {case 1:case 2:case 3: output(123); break; // 1,2,3共享代码case 4: output(40);case 5: output(50); break; // 4会fall through到5default: output(0); break;}
}// 5. 枚举类型的switch
enum class Color { RED, GREEN, BLUE, YELLOW, BLACK };void switch_enum(Color color) {switch (color) {case Color::RED: output(1); break;case Color::GREEN: output(2); break;case Color::BLUE: output(3); break;case Color::YELLOW: output(4); break;default: output(0); break;}
}// 6. 字符类型switch
void switch_char(char c) {switch (c) {case 'A': case 'a': output(65); break;case 'B': case 'b': output(66); break;case 'C': case 'c': output(67); break;default: output(0); break;}
}// 7. 边界测试:最小/最大值差距大但case少
void switch_large_range(int value) {switch (value) {case 0: output(0); break;case 1000: output(1000); break;case 1000000: output(1000000); break;default: output(-1); break;}
}// 8. 嵌套switch语句
void switch_nested(int x, int y) {switch (x) {case 1:switch (y) {case 1: output(11); break;case 2: output(12); break;default: output(10); break;}break;case 2:switch (y) {case 1: output(21); break;case 2: output(22); break;default: output(20); break;}break;default: output(0); break;}
}// 9. 只有少量case的情况
void switch_few_cases(int value) {switch (value) {case 1: output(1); break;case 2: output(2); break;default: output(0); break;}
}// 10. 用于状态机的switch(典型应用)
void state_machine_example() {enum State { START, PROCESSING, END };static State state = START;static int counter = 0;switch (state) {case START:counter = 0;state = PROCESSING;break;case PROCESSING:counter++;if (counter >= 5) state = END;break;case END:output(999);break;}
}// 测试函数
int main() {// 测试各种switch情况switch_dense_sequential(3); // 密集连续switch_sparse(50); // 稀疏值switch_small_gaps(5); // 小间隔switch_fallthrough(4); // fall-throughswitch_enum(Color::GREEN); // 枚举switch_char('b'); // 字符switch_large_range(1000); // 大范围switch_nested(1, 2); // 嵌套switch_few_cases(1); // 少量case// 状态机多次执行for (int i = 0; i < 10; i++) {state_machine_example();}return 0;
}
汇编部分
26: // 2. 稀疏值 - 可能生成条件跳转链27: void switch_sparse(int value) {
00A520D0 push ebp
00A520D1 mov ebp,esp
00A520D3 sub esp,0C4h
00A520D9 push ebx
00A520DA push esi
00A520DB push edi
00A520DC lea edi,[ebp-4]
00A520DF mov ecx,1
00A520E4 mov eax,0CCCCCCCCh
00A520E9 rep stos dword ptr es:[edi]
00A520EB mov ecx,offset _FA199733_if语句@cpp (0A5D058h)
00A520F0 call @__CheckForDebuggerJustMyCode@4 (0A51348h)
00A520F5 nop 28: switch (value) {
00A520F6 mov eax,dword ptr [value]
00A520F9 mov dword ptr [ebp-0C4h],eax
00A520FF cmp dword ptr [ebp-0C4h],64h
00A52106 jg __$EncStackInitStart+49h (0A52125h)
00A52108 cmp dword ptr [ebp-0C4h],64h
00A5210F je __$EncStackInitStart+75h (0A52151h)
00A52111 cmp dword ptr [ebp-0C4h],0Ah
00A52118 je __$EncStackInitStart+57h (0A52133h)
00A5211A cmp dword ptr [ebp-0C4h],32h
00A52121 je __$EncStackInitStart+66h (0A52142h)
00A52123 jmp __$EncStackInitStart+93h (0A5216Fh)
00A52125 cmp dword ptr [ebp-0C4h],1F4h
00A5212F je __$EncStackInitStart+84h (0A52160h)
00A52131 jmp __$EncStackInitStart+93h (0A5216Fh) 29: case 10: output(1000); break;
00A52133 push 3E8h
00A52138 call output (0A5105Ah)
00A5213D add esp,4
00A52140 jmp __$EncStackInitStart+9Dh (0A52179h) 30: case 50: output(5000); break;
00A52142 push 1388h
00A52147 call output (0A5105Ah)
00A5214C add esp,4
00A5214F jmp __$EncStackInitStart+9Dh (0A52179h) 31: case 100: output(10000); break;
00A52151 push 2710h
00A52156 call output (0A5105Ah)
00A5215B add esp,4
00A5215E jmp __$EncStackInitStart+9Dh (0A52179h) 32: case 500: output(50000); break;
00A52160 push 0C350h
00A52165 call output (0A5105Ah)
00A5216A add esp,4
00A5216D jmp __$EncStackInitStart+9Dh (0A52179h) 33: default: output(0); break;
00A5216F push 0
00A52171 call output (0A5105Ah)
00A52176 add esp,4 34: }35: }
00A52179 pop edi
00A5217A pop esi
00A5217B pop ebx
00A5217C add esp,0C4h
00A52182 cmp ebp,esp
00A52184 call __RTC_CheckEsp (0A51258h)
00A52189 mov esp,ebp
00A5218B pop ebp
00A5218C ret
根据提供的汇编代码,这是一个稀疏值(sparse)的switch-case语句,编译器生成了**条件跳转链(if-else链)**的实现方式。
汇编特征分析
1. 初始比较和分支
00A520F6 mov eax,dword ptr [value]
00A520F9 mov dword ptr [ebp-0C4h],eax
00A520FF cmp dword ptr [ebp-0C4h],64h ; 比较 value 和 100
00A52106 jg 0A52125h ; 大于100跳转
00A52108 cmp dword ptr [ebp-0C4h],64h ; 再次比较100
00A5210F je 0A52151h ; 等于100跳转(case 100)
00A52111 cmp dword ptr [ebp-0C4h],0Ah ; 比较10
00A52118 je 0A52133h ; 等于10跳转(case 10)
00A5211A cmp dword ptr [ebp-0C4h],32h ; 比较50
00A52121 je 0A52142h ; 等于50跳转(case 50)
00A52123 jmp 0A5216Fh ; 跳转到default
2. 大于100的分支处理
00A52125 cmp dword ptr [ebp-0C4h],1F4h ; 比较500
00A5212F je 0A52160h ; 等于500跳转(case 500)
00A52131 jmp 0A5216Fh ; 跳转到default
3. 各case块执行
; case 10
00A52133 push 3E8h ; 1000
00A52138 call output
00A52140 jmp 0A52179h ; 跳出switch; case 50
00A52142 push 1388h ; 5000
00A52147 call output
00A5214F jmp 0A52179h; case 100
00A52151 push 2710h ; 10000
00A52156 call output
00A5215E jmp 0A52179h; case 500
00A52160 push 0C350h ; 50000
00A52165 call output
00A5216D jmp 0A52179h; default
00A5216F push 0
00A52171 call output
关键特征总结
- 条件跳转链: 使用连续的
cmp
和条件跳转指令(je
,jg
)来测试每个case值 - 二分搜索优化: 先比较中间值(100),然后分别处理小于等于和大于的情况
- 没有跳转表: 由于case值稀疏(10, 50, 100, 500),编译器没有生成跳转表
- 线性搜索: 在各自的分支内,case值是线性比较的
- 明确的边界检查: 通过比较指令建立明确的执行路径
对应的C++代码推测
void switch_sparse(int value) {switch (value) {case 10: output(1000); break;case 50: output(5000); break; case 100: output(10000); break;case 500: output(50000); break;default: output(0); break;}
}
这种实现方式在case值较少且分布稀疏时效率较高,避免了大型跳转表的内存开销。