switch语句导致程序跑飞,换成if-else就可以
最近在做一个项目,需要在SRAM中调用flash中已经烧好的函数,但是在跑的时候程序总是跑飞,找了半天居然是switch捣的鬼,换成if-else就没问题了。这还要从两者的底层逻辑来看。
在C语言的程序开发中,最常用的两种分支结构就是if-else条件语句和switch多分支选择语句。二者都能实现“满足不同条件、执行不同代码”的功能。如下面两段代码
int grade = 2; switch (grade) { case 1: printf("一年级"); break; case 2: printf("二年级"); break; case 3: printf("三年级"); break; default: printf("未知年级"); }int grade = 2; if (grade == 1) { printf("一年级"); } else if (grade == 2) { printf("二年级"); } else if (grade == 3) { printf("三年级"); } else { printf("未知年级"); }一般认为当分支条件较多的时候,switch的执行效率是要更高的,根本原因是两者的执行机制完全不同:
1. if-else:暴力遍历,逐条判断
多分支if-else if-else是从上到下顺序执行。假设你有 5 个分支,匹配的是最后一个条件:程序必须先白白计算、判断前面 4 个错误条件,全部走完,才会执行最后一个正确分支。分支越多,无效判断越多,速度越慢,耗时随分支数量线性增加。
2. switch:预建表格,精准跳转
switch 在编译代码的时候,编译器就提前干完了所有准备工作:把所有 case 的值和代码地址,整理成一张跳转表(索引表)。程序运行时只做一步:算出变量值 → 直接查表 →瞬间跳转到对应代码不需要遍历前面任何分支。无论你写 3 个分支还是 100 个分支,跳转耗时完全一样、恒定不变。
出现的问题就是,如果flash中的函数中包含switch函数,在SRAM中执行,访问flash中的跳转表时出现错误。(这个问题跟CPU类型相关,arm一般不会出现这个问题,我所用的CPU的指令缓存只缓存指令,不缓存数据表,所以在SRAM中会跑飞,在flash中就不会有问题)。
此外还有一个问题,当 switch 很短(≤3~4 个 case),编译器不会生成跳转表,而是直接翻译成if-else语句。
