<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一個switch case引起的線上故障

          共 6408字,需瀏覽 13分鐘

           ·

          2021-12-28 00:59

          故障過程

          1、上午的時候,QA同學(xué)突然說,測試自動化的流程突然過不去了,問我是不是最近對線上做了某些修改。當(dāng)時第一反應(yīng)是不可能

          2、通過QA同學(xué)提供的test case,在測試環(huán)境通過curl發(fā)送請求,發(fā)現(xiàn)果然廣告返回值跟預(yù)期不符。

          3、通過git log對比,發(fā)現(xiàn)近期只有一個switch語句有修改。

          4、嘗試在代碼中加入log語句,發(fā)現(xiàn)日志輸出果然跟QA的錯誤結(jié)果一致,至此原因找到。

          故障原因

          下面是錯誤代碼

          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;
          ??????}

          發(fā)現(xiàn),當(dāng)dsp_res->bid_type() == 2的時候,也會執(zhí)行 case 3的部分,然后嘗試在上面各個"do sth" 后面,加上break,結(jié)果符合預(yù)期,bug搞定。

          深思

          為什么在未增加新case之前,test case能通過呢?仔細找QA問了下case的邏輯,原來,case每次都會返回bid_type = 2。此處,我們再貼一次之前的代碼:

          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,導(dǎo)致會把case 2 和 case 3的代碼都執(zhí)行了,直到退出循環(huán)或者遇到break。此處列下switch case的三個規(guī)則:switch...case的三個規(guī)則:

          1. 既無成功匹配,又無default子句,那么swtich語句塊什么也不做;
          2. 無成功匹配,但有default,那么swtich語句塊做default語句塊的事;
          3. 有成功匹配,沒有break,那么成功匹配后,一直執(zhí)行,直到遇到break。

          看來我們的線上bug是因為遇到了第三個規(guī)則導(dǎo)致。

          擴展

          語句體中不包含break

          #include?
          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;
          }

          當(dāng)輸入choice 為 1的時候

          當(dāng)輸入choice 為 2的時候

          原因:

          在上面的示例中,如果iChoice等于1,則執(zhí)行主體的所有語句,因為在開關(guān)主體中沒有出現(xiàn)break語句。如果ichoice等于2,則由于沒有break語句,因此控制跳至情況2并執(zhí)行以下所有情況。

          一個執(zhí)行語句被多個case命中

          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,都會執(zhí)行到TestFunction

          存在一樣的case標(biāo)簽

          #include?
          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標(biāo)簽不能重復(fù),否則編譯器不能確定進入哪個標(biāo)簽

          case值為浮點數(shù)

          #include?
          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 中的參數(shù)必須可以轉(zhuǎn)換成一個整數(shù)

          將default 語句放在正文的其他地方

          #include?
          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標(biāo)簽值必須為常量

          #include?
          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;
          }

          輸出:

          嵌套開關(guān)

          #include?
          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;
          }

          輸出:

          心得

          平時編碼中,一定要注意編碼規(guī)范,每個case都寫好對應(yīng)的break,不要學(xué)習(xí)這種騷操作,稍不注意就可能出現(xiàn)線上故障。


          END

          瀏覽 125
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  青娱视频日韩精品 | 日韩性爱小视频 | 国产成人性爱视频 | 色欲影视淫香淫色 | 国产乱伦AV无码 |