Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >一个switch case引起的线上bug

一个switch case引起的线上bug

原创
作者头像
高性能架构探索
修改于 2021-04-08 03:25:07
修改于 2021-04-08 03:25:07
76400
代码可运行
举报
文章被收录于专栏:技术随笔心得技术随笔心得
运行总次数:0
代码可运行

​故障过程

1、上午的时候,QA同学突然说,测试自动化的流程突然过不去了,问我是不是最近对线上做了某些修改。当时第一反应是不可能

2、通过QA同学提供的test case,在测试环境通过curl发送请求,发现果然广告返回值跟预期不符。

3、通过git log对比,发现近期只有一个switch语句有修改。

4、尝试在代码中加入log语句,发现日志输出果然跟QA的错误结果一致,至此原因找到。

故障原因

下面是错误代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
switch (dsp_res->bid_type()) {
        case 0:
        {
          auto info = dsp_response->add_dsp_res_infos();
          info->set_dsp_id(item.dsp_id());
          if (dsp_res->has_cache_duration()) {
            info->set_duration(dsp_res->cache_duration());
          }
          if (dsp_res->has_quality()) {
            info->set_ratio(dsp_res->quality());
          }
    // do sth
        }
        case 1:
          break;
        case 2:
        {
          auto info = dsp_response->add_dsp_res_infos();
          if (dsp_res->has_cache_duration()) {
            info->set_duration(dsp_res->cache_duration());
          }

          if (dsp_res->has_quality()) {
            info->set_ratio(dsp_res->quality());
          }

          info->set_dsp_id(item.dsp_id());
          std::unordered_set<std::string> adids;
          for (auto elem : dsp_res->ad_ids()) {
            adids.insert(elem);
          }
    // do sth
          
        }
        case 3: // 此case为新增
        {
          auto info = dsp_response->add_dsp_res_infos();
          info->set_dsp_id(item.dsp_id());
          if (dsp_res->has_cache_duration()) {
            info->set_duration(dsp_res->cache_duration());
          }
          if (dsp_res->has_quality()) {
            info->set_ratio(dsp_res->quality());
          }
    // do sth
        }
        default:
          break;
      }

发现,当dsp_res->bid_type() == 2的时候,也会执行 case 3的部分,然后尝试在上面各个"do sth" 后面,加上break,结果符合预期,bug搞定。

深思

为什么在未增加新case之前,test case能通过呢?仔细找QA问了下case的逻辑,原来,case每次都会返回bid_type = 2。此处,我们再贴一次之前的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
switch (dsp_res->bid_type()) {
        case 0:
        {
          auto info = dsp_response->add_dsp_res_infos();
          info->set_dsp_id(item.dsp_id());
          if (dsp_res->has_cache_duration()) {
            info->set_duration(dsp_res->cache_duration());
          }
          if (dsp_res->has_quality()) {
            info->set_ratio(dsp_res->quality());
          }
    // do sth
        }
        case 1:
          break;
        case 2:
        {
          auto info = dsp_response->add_dsp_res_infos();
          if (dsp_res->has_cache_duration()) {
            info->set_duration(dsp_res->cache_duration());
          }

          if (dsp_res->has_quality()) {
            info->set_ratio(dsp_res->quality());
          }

          info->set_dsp_id(item.dsp_id());
          std::unordered_set<std::string> adids;
          for (auto elem : dsp_res->ad_ids()) {
            adids.insert(elem);
          }
    // do sth
        }
        default:
          break;
      }

由于switch每次都会进入case 2的子逻辑,该逻辑后面就是default,然后break,没问题。但是增加了新case 3之后,因为case 2 和 case 3后面都没有break,导致会把case 2 和 case 3的代码都执行了,直到退出循环或者遇到break。此处列下switch case的三个规则:switch...case的三个规则:

  1. 既无成功匹配,又无default子句,那么swtich语句块什么也不做;
  2. 无成功匹配,但有default,那么swtich语句块做default语句块的事;
  3. 有成功匹配,没有break,那么成功匹配后,一直执行,直到遇到break。

看来我们的线上bug是因为遇到了第三个规则导致。

扩展

语句体中不包含break

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
    int iChoice = 0;
    printf("Enter your choice = ");
    scanf( "%d",&iChoice);
    switch (iChoice)
    {
    case 1:
        printf("case 1 !\n");
    case 2:
        printf("case 2 !\n");
    case 3:
        printf("case 3 !\n");
    default:
        printf("default !\n" );
    }
    return 0;
}

当输入choice 为 1的时候

当输入choice 为 2的时候

原因:

在上面的示例中,如果iChoice等于1,则执行主体的所有语句,因为在开关主体中没有出现break语句。如果ichoice等于2,则由于没有break语句,因此控制跳至情况2并执行以下所有情况。

一个执行语句被多个case命中

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void TestFunction(void)
{
    printf("Demo code\n");
}
int main()
{
    int iChoice = 0;
    printf("Enter your choice = ");
    scanf( "%d", &iChoice);
    switch ( iChoice )
    {
    case 1:
    case 2:
    case 3:
        //Calling function
        TestFunction();
        break;
    case 4:
        printf("Wow Test paas !");
        break;
    default:
        printf("default !\n" );
    }
    return 0;
}

输出为

原因:

对于case 1 2 3,都会执行到TestFunction

存在一样的case标签

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
    int iChoice   = 0;
    int i = 0;
    printf("Enter your choice = ");
    scanf( "%d", &iChoice);
    switch ( iChoice )
    {
    case 1:
        i++;
        break;
    case 3:
        i = i + 2;
        break;
    case 3:
        i = i + 3;
        break;
    default:
        printf("default !\n" );
        break;
    }
    printf("Value of i = %d",i);
    return 0;
}

输出

原因

case标签不能重复,否则编译器不能确定进入哪个标签

case值为浮点数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
    int iChoice   = 0;
    int i = 0;
    printf("Enter your choice = ");
    scanf( "%d", &iChoice);
    switch (iChoice)
    {
    case 1:
        i++;
        break;
    case 2.5:
        i = i + 2;
        break;
    case 3:
        i = i + 3;
        break;
    default:
        printf("default !\n" );
    }
    printf("Value of i = %d",i);
    return 0;
}

输出:

原因:

switch 中的参数必须可以转换成一个整数

将default 语句放在正文的其他地方

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
    int iChoice  = 0;
    printf("Enter your choice = ");
    scanf( "%d", &iChoice);
    switch (iChoice)
    {
    default:
        printf("Bad Input !\n");
        break;
    case 1:
        printf("Your enter choice is 1\n");
        break;
    case 2:
        printf("Your enter choice is 2\n");
        break;
    case 3:
        printf("Your enter choice is 3\n");
        break;
    }
    return 0;
}

输出:

case标签值必须为常量

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
    int iChoice  = 0;
    int Label = 1;
    printf("Enter your choice = ");
    scanf( "%d", &iChoice);
    switch (iChoice)
    {
    case Label:
        printf("Your enter choice is 1\n");
        break;
    case 2:
        printf("Your enter choice is 2\n");
        break;
    case 3:
        printf("Your enter choice is 3\n");
        break;
    default:
        printf("Bad Input !\n");
        break;
    }
    return 0;
}

输出:

嵌套开关

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void nestedSwitchDemo(int input1, int input2)
{
    switch (input1)
    {
    case 1:
        printf("Your enter choice is 1\n");
        switch (input2 )
        {
        case 1:
            printf("Enter Sub choice is 1\n");
            break;
        case 2:
            printf("Enter Sub choice is 2\n");
            break;
        }
        break;
    case 2:
        printf("Your enter choice is 2\n");
        break;
    case 3:
        printf("Your enter choice is 3\n");
        break;
    default:
        printf("Bad Input !\n");
        break;
    }
}
int main()
{
    int iChoice  = 1;
    int iSubChoice = 1;
    //Calling function
    nestedSwitchDemo(iChoice,iSubChoice);
    return 0;
}

输出:

心得

平时编码中,一定要注意编码规范,每个case都写好对应的break,不要学习这种骚操作,稍不注意就可能出现线上故障。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C语言实现数独小游戏
C语言控制台数独游戏,注释详细 效果图 #include <stdio.h> #include <stdlib.h> #include <memory.h> #include <math.h> #include <time.h> #include <windows.h> #include <string.h> #include <conio.h> #include <stdarg.h> #include <ctype.h> #define MAX 999 #define MAXN 9 ty
程序员小涛
2022/05/07
2K0
C语言实现数独小游戏
C语言循环与分支不会用?来看看!
while 和 for 这两种循环都是先判断,条件如果满⾜就进⼊循环,执⾏循环语句,如果不满⾜就跳 出循环; ⽽ d o while 循环则是先直接进⼊循环体,执⾏循环语句,然后再执⾏ 达式为真,就会进⾏下⼀次,表达式为假,则不再继续循环。
秋邱
2024/10/09
1460
C语言循环与分支不会用?来看看!
C语言 第四章 分支结构练习
该文讨论了技术社区中内容编辑人员的一些职责和日常工作。主要包括了管理社区的提问和回答,处理问题反馈和用户咨询,以及进行社区内容的策划和编辑。此外,还需要与社区的管理员协作,确保社区的内容质量和氛围。
张果
2018/01/03
8840
C语言 第四章 分支结构练习
C语言结构
风中的云彩
2024/11/07
900
C语言结构
C语言之超市商品管理系统
本文介绍了一个基于C语言实现的超市商品管理系统,旨在为管理员和消费者提供高效的商品管理与购物体验。系统通过简洁的设计和实用的功能模块,满足了小型超市或零售店的日常运营需求。
刘君
2025/01/21
1700
C语言之超市商品管理系统
C语言 第四章 关系、逻辑运算与分支流程控制
张果
2018/01/03
8040
C语言 第四章 关系、逻辑运算与分支流程控制
C-switch case之如何巧妙判断范围区域
当判断整数时 示例: 判断整数范围 #include <stdio.h> int main() { unsigned char buf[6]={0x00,0x07,0x11,0x60,0x61,0x66}; for(int i=0;i<6;i++) switch(buf[i]) { case 0x00 ... 0x10: printf("buf[%d] is 0x0 ~0x10\n",i); break; case 0x1
诺谦
2018/12/25
2.1K0
【C语言】简易计算器转移表(函数指针简化)
转移表是一种根据输入条件进行分支选择的技术。它通常用于根据不同的条件执行不同的操作。在 C 语言中,我们可以使用 switch 语句来创建转移表,根据表达式的值选择不同的分支执行。
DevKevin
2024/03/19
1440
【C语言】简易计算器转移表(函数指针简化)
C语言/动态通讯录
为了使用通讯录时,可以随时调整大小,所以使用动态开辟内存函数写通讯录,可增加联系人容量。
用户10788736
2023/10/16
2540
C语言/动态通讯录
【C语言程序设计——选择结构程序设计】预测你的身高(头歌实践教学平台习题)【合集】
这里,switch表达式choice的值会依次与case 1、case 2、case 3进行比较,如果choice等于1,就会执行printf("打开文件\n");,然后遇到break语句,跳出switch结构;如果choice的值与所有case常量都不匹配,就会执行default分支下的语句,提示用户输入无效。
Rossy Yan
2024/12/27
1080
【C语言程序设计——选择结构程序设计】预测你的身高(头歌实践教学平台习题)【合集】
【C语言】扫雷(可展开空白版与鼠标操作版)
扫雷游戏是一款经典的单人电脑游戏,最初由微软公司开发。玩家需要根据数字提示,在不触雷的情况下揭开所有格子。这是一款考验逻辑思维和运气的游戏,而我们将用C语言来实现它。
DevKevin
2024/03/19
1350
分支和循环(上)
在if else语句中,else可以与另一个if语句连用,构成多重判断。 第一种:
四念处茫茫
2025/01/31
660
分支和循环(上)
查询自动售货机中的商品价格
一、题目描述 假设自动售货机出售四种商品,在屏幕上显示以下菜单(编号和选项),用户可以连续查询商品的价格,当查询次数超过5次时,自动退出查询;不到5次时,用户可以选择退出。当用户输入编号1~4,显示相应的商品价格(保留1位小数);输入0,退出查询;输入其他编号,显示价格为0. 二、所需技能 if 、switch 语句 for 循环 数据类型转换 三、代码实现 int choice,i; double price; for(i=1;i<=5;i++){ //以下5行显示
Zoctopus
2018/06/04
1.1K0
小朋友学C语言(29):switch case语句
switch case语句与if elseif语句类似,都是从多个选择条件里选取一个来执行。 (一)先来看一个if elseif程序 #include <stdio.h> int main() { int number; printf("Please input an integer between 1~7: "); scanf("%d", &number); printf("Today is "); if(1 == number) { p
海天一树
2018/04/17
1K0
【C语言】判断语句以及分支语句《详细讲解》
简介:除了可以指定在条件为真时候执行某些语句外,还可以执行另外一段代码。在C语言中是利用 else语句完成得,其一般形式如下:
謓泽
2022/12/12
7420
【C语言】判断语句以及分支语句《详细讲解》
【C语言】自学终极笔记
函数包括:函数首部(第一行)+函数体(‘{’+内容+‘}‘),函数体=函数声明(即函数原型)+执行部分。
SarPro
2024/02/20
1850
【C语言】自学终极笔记
c语言从入门到实战——分支和循环
C语言是结构化的程序设计语言,这里的结构指的是顺序结构、选择结构、循环结构,C语言是能够实 现这三种结构的,其实我们如果仔细分析,我们日常所见的事情都可以拆分为这三种结构或者这三种结构的组合。
鲜于言悠
2024/03/20
2200
c语言从入门到实战——分支和循环
详解C语言分支与循环语句
这样吧,你先在steam搜索“千恋*万花”点击购买安装好后立即运行打开千恋万花,在主页面点击开始游戏进入游戏页面,然后依次选择“说实话”、“不好说”、“觉得很可爱”、“单独行动”、“摸摸头”、“有点担心”和“安抚”进入丛雨路线 没错,galgame中的选项就是选择语句。
Yui_
2024/10/15
1190
详解C语言分支与循环语句
C语言初阶——分支语句(if,switch)
要学习分支语句和循环语句,首先我们要知道什么是语句。 在C语言中,由一个分号隔开的就是一条语句。 比如:
YIN_尹
2024/01/23
1710
C语言初阶——分支语句(if,switch)
C语言-语句(if,for,while,switch,goto,return,break,continue)
第二章介绍语法使用规则、使用案例,第三章列出了一些练习题,用于结合第二章介绍的语句完成知识点巩固。
DS小龙哥
2022/01/07
9930
相关推荐
C语言实现数独小游戏
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验