1. 程式人生 > 其它 >c++ error函式_【C進階】"最常見"卻又"最不常用"的三個預編譯

c++ error函式_【C進階】"最常見"卻又"最不常用"的三個預編譯

技術標籤:c++ error函式c++未定義識別符號怎麼解決

d8391163ff407f8f8ebb3a1f214ef0ff.gif

1、聊一聊

喜歡籃球的小夥伴應該都知道為什麼會選擇這樣 一首略帶悲傷的歌曲 吧 。

本文主要跟大家講解三個在編碼過程中用得比較少的預編譯,他們分別是#error、#warning、#undef ,以便更好的為我們編碼服務。

82d2e3985de0e7c18f2b9b2982f42a74.png

2、情景再現

6a49982e39cce014cdf2a0fdfa29a032.png13aaddaa06e7ae9eb99a69b911a021aa.png

咬金,C語言學得怎麼樣了?

我都敲了2年C程式碼了,還有我不知道的嗎?

54993bfc55debc8397152a8bdf7d2386.png b9b5df1361bbdfb7d71767873d99c9ff.png 6a49982e39cce014cdf2a0fdfa29a032.png13aaddaa06e7ae9eb99a69b911a021aa.png

你狂,你繼續狂!那我問你#error,#warning,#def這三個預編譯幹啥的?

額~~~,這就尷尬了,平時看程式碼基本上都見過,沒怎麼研究過哦。

54993bfc55debc8397152a8bdf7d2386.png b9b5df1361bbdfb7d71767873d99c9ff.png 6a49982e39cce014cdf2a0fdfa29a032.png13aaddaa06e7ae9eb99a69b911a021aa.png

哈哈~,要不要我教教你呀?

小魯班,跟大哥說說唄!

54993bfc55debc8397152a8bdf7d2386.png b9b5df1361bbdfb7d71767873d99c9ff.png 6a49982e39cce014cdf2a0fdfa29a032.png13aaddaa06e7ae9eb99a69b911a021aa.png

行吧,待會說我這隊友啥也不懂!

1

#error 與#warning

談到預編譯大家常用的有#if、#else、#ifdef、#ifndef、#endif等等條件編譯選項。

然而在我們閱讀一些大型的程式碼或者庫的時候,一般都會看到有#error和#warning,可能有些小夥伴一掃而過並沒有瞭解清楚這些預編譯指令到底該怎麼用,寫了很久的程式碼估計也重來沒有敲過他們。

  • #error / #warning

  • 形式 :#error / #warning message

  • 作用 :生成一個編譯錯誤事件並停止編譯/發出警告資訊

  • 注意 :message可以不需要雙引號。

參考demo:
#include
#include//#defineconfigUART_N5
#ifndefconfigUART_N
#errorconfigUART_Nmustdefine//#error"configUARTmustdefine"//#warning"configUARTmustdefine"
#endif
#ifconfigUART_N>4
#errorconfigUART_Nmustnotbelessthan4//#error"configUART_Nmustnotbelessthan4"//#warning"configUART_Nmustnotbelessthan4"
#endif/***************************************
*Fuction:進行預編譯測試
*Author:(最後一個bug)
**************************************/
intmain(intargc,char*argv[]){
printf("公眾號;最後一個bug\n");return0;
}
輸出結果:

c31d2f8e384fc8f351b869e8723d37e9.png

  • 編譯失敗,無法生成可執行檔案

a31a785ac59828b70629dc068499455c.png

  • 上面是放開巨集,且使用warning的情況,無其他錯誤的情況下可以生成可執行檔案。

解釋一下:
  • 通過上面的測試程式碼可以瞭解到,通過配合條件預編譯#if等,#error和#warning能夠在編譯過程中分別以錯誤和告警的形式提醒開發人員注意相關程式碼設計問題,從而保證程式碼正確性。

  • 這樣對於釋出一些龐大的庫程式碼時,為了讓開發人員正確的使用庫,這些提示會幫助他更好的移植程式碼。

  • 那麼經常有很多小夥伴編譯出來的程式碼有一大堆warning,總是覺得warning關係不大,然而warning也是分不同型別的,對於一些未使用的變數倒關係不大,其他情況還是要認真對待,最好是做到"0 Error,0 warning".

2

#undef

#undef識別符號用於把前面的巨集定義名取消,別看這巨集用得不多,作用可大著呢,下面我簡單舉幾個例子:

1

區域性巨集定義

一旦定義了巨集,那麼該檔案中往下所有的程式碼都可以使用該巨集,即使是函式內部,這樣導致巨集比較混亂,如下面程式碼:

參考demo:
#include
#include
#defineconfigRatio10/***************************************
*Fuction:獲得感測器電壓值
*Author:(最後一個bug)
**************************************/
intGetSensorVolt(void)
{
#defineconfigRatio1
intret=0;
ret=configRatio*1024;//比例因子*AD值returnret;//#undefconfigRatio
}/***************************************
*Fuction:獲得感測器電壓值
*Author:(最後一個bug)
**************************************/
intGetSensorCurr(void)
{
#defineconfigRatio2
intret=0;
ret=configRatio*1024;//比例因子*AD值returnret;//#undefconfigRatio
}/***************************************
*Fuction:進行預編譯測試
*Author:(最後一個bug)
**************************************/
intmain(intargc,char*argv[]){
printf("configRatio=%d\n",configRatio);//報巨集未定義
printf("GetSensorVolt=%d\n",GetSensorVolt());
printf("GetSensorCurr=%d\n",GetSensorCurr());
printf("公眾號;最後一個bug\n");return0;
}
輸出結果:

a4042d42ba3f939773e333685383b7c7.png

b8252cad2e8fdf2bad1e56c95642d412.png

解釋一下:
  • 假如我們沒有注意到函式內部的同名巨集定義,當然告警也沒管,那麼在main函式中使用同名巨集定義就可能不是我們期待的最上面的巨集定義,造成程式bug。

  • 所以我們可以使用#undef來限制每個巨集的作用域,如果每個函式內部都使用了#undef,那麼main函式中再使用會報巨集沒有定義,這樣便可以找到問題,當然也可以通過警告瞭解到。

2

‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍選擇介面

通過巨集來切換不同的介面供程式使用:

參考demo:
#include
#include
#include
#defineDEV_SPI
#include"Drive.h"
#undefDEV_SPI/***************************************
*Fuction:進行預編譯測試
*Author:(最後一個bug)
**************************************/
intmain(intargc,char*argv[]){
char*strbug="thelastbug";
SendData(strbug);
ProcessData(strbug);
printf("公眾號;最後一個bug\n");return0;
}
#include
#ifdefDEV_UART
#defineSendData(s)printf("UARTSend:%s\n",s)
#defineProcessData(s)printf("UARTProcess:%s\n",s)
#endif
#ifdefDEV_CAN
#defineSendData(s)printf("CANSend:%s\n",s)
#defineProcessData(s)printf("CANProcess:%s\n",s)
#endif
#ifdefDEV_SPI
#defineSendData(s)printf("SpiSend:%s\n",s)
#defineProcessData(s)printf("SpiProcess:%s\n",s)
#endif
輸出結果:

9df23b5d40e0797bb1f10c7177c493cd.png

‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍3

‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍ ‍

自定義介面

當多個人維護一套程式碼的時候,有些同事喜歡呼叫庫函式介面,而有些同事喜歡呼叫自定義介面,為了方便統一使用自定義介面或者庫介面,我們會進行如下操作:

參考demo:
#include
#include
#include
#include"Drive.h"//#undefprintf/***************************************
*Fuction:進行預編譯測試
*Author:(最後一個bug)
**************************************/
intmain(intargc,char*argv[]){
char*strbug="thelastbug";
printf("公眾號;最後一個bug\n");return0;
}
#ifndef__DRIVE_H__
#define__DRIVE_H__

#defineprintfprintf("pleaseuseKprintf!\n");

externvoidKprintf(char*str);

#endif
輸出結果:

98241c986e4d8435628c11888e4f643d.png

  • 這樣下面的程式碼你就只能夠使用Kprintf來進行輸出列印,而當我們放開註釋掉的巨集,這樣就又可以使用printf了,還是比較方便的。

6a49982e39cce014cdf2a0fdfa29a032.png13aaddaa06e7ae9eb99a69b911a021aa.png

咬金,懂了沒 ?

小魯班,這些知識都被你學到了!666

54993bfc55debc8397152a8bdf7d2386.png b9b5df1361bbdfb7d71767873d99c9ff.png

3、結束語

上面這幾個比較"冷門"的知識認真想想其實還是挺有用的,可能現在的產品都急於快速上市,對於程式碼的雕琢還有所欠缺的,一份成熟的程式碼不僅僅只是穩定,還有後期的維護、擴充套件等等都是值得考慮的。

好了,這裡是公眾號:“最後一個bug”,一個為大家打造的技術知識提升基地,如果你喜歡交流可以新增下方bug菌微信,我拉你加入公眾號技術交流群。

b686b60efeda091045f2e657bcc05e9d.png

推薦好文點選藍色字型即可跳轉

☞【開源】bug菌把"動態數字顯示"開源了!ac8e6d8e28ad539c5892129553e4eb60.gif

☞【C進階】同事笑我 : 有了"巨集"你還用"列舉"幹嘛?ac8e6d8e28ad539c5892129553e4eb60.gif

☞【MCU】U-boot2020移植到stm32F4,效果槓槓的!

☞【進階】同事用#include"xxx.c"把我給驚呆了!!

9064e7688a4acdec7afdda4d76507e10.gif