你是否被要求寫(xiě)的代碼需要0 erros, 0 warnings? 或者你的項(xiàng)目是否需要做靜態(tài)代碼檢測(cè)?0 erros是一定要做到,而0 wanring有時(shí)候會(huì)讓你抓狂。前面轉(zhuǎn)了一篇數(shù)組內(nèi)包含頭文件的寫(xiě)法,看起來(lái)對(duì)此類不太常見(jiàn)的寫(xiě)法大家比較感興趣,今天來(lái)分享一個(gè)去除函數(shù)參數(shù)未使用warning的技巧。使用void即可輕松去除,如果你知道怎么用,可以關(guān)閉此文了,因?yàn)楹芎?jiǎn)單。沒(méi)用過(guò)的則可以學(xué)習(xí)學(xué)習(xí)。
先舉個(gè)栗子
看一個(gè)都熟悉經(jīng)典栗子:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("Hello World\n");
return 0;
}
這程序簡(jiǎn)單吧?不能再簡(jiǎn)單了!編譯運(yùn)行正常,看到了Hello World,編譯也沒(méi)有錯(cuò):
But,卻有兩個(gè)warning! 嗯?這樣一個(gè)沙雕代碼,管它是否warning!沒(méi)錯(cuò),這里確實(shí)可以不去管??墒侨绻阕鲆恍┨厥庑袠I(yè)的嵌入式開(kāi)發(fā),比如汽車、醫(yī)療、工控、軍工等,其代碼都可能要求做靜態(tài)代碼檢測(cè),如果你函數(shù)中的參數(shù)沒(méi)被使用,就一定會(huì)拋出這樣的警告!要求嚴(yán)格的企業(yè),這樣的代碼是不可以提交的,比如工業(yè)做IEC61508功能安全認(rèn)證,代碼是需要提交給認(rèn)證機(jī)構(gòu)審查的,這樣帶warning的,你還想拿證嗎?同樣在醫(yī)療、汽車領(lǐng)域,則要求就更為嚴(yán)謹(jǐn)了,就更遑論軍工了。
那么怎么整呢?
且看lwip的做法
在\src\include\lwip\Arch.h中定義了這樣一個(gè)宏:
#ifndef LWIP_UNUSED_ARG
#define LWIP_UNUSED_ARG(x) (void)x
#endif /* LWIP_UNUSED_ARG */
讓我們來(lái)隨便搜一個(gè)使用的地方:
err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
{
#if LWIP_TCP
struct api_msg msg;
err_t err;
/* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
LWIP_UNUSED_ARG(backlog);
LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_listen;
msg.msg.conn = conn;
#if TCP_LISTEN_BACKLOG
msg.msg.msg.lb.backlog = backlog;
#endif /* TCP_LISTEN_BACKLOG */
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(backlog);
return ERR_ARG;
#endif /* LWIP_TCP */
}
你看,這個(gè)函數(shù)里有三處使用這個(gè)宏?細(xì)心的童鞋可能會(huì)說(shuō),既然不用函數(shù)參數(shù)原型把它干掉不就好了嗎?這里有兩個(gè)原因:
- 其一、有的參數(shù)在開(kāi)發(fā)中可能是預(yù)留接口,項(xiàng)目是不斷迭代開(kāi)發(fā)的,有些功能可能剛開(kāi)始沒(méi)做,但是接口有可能提前定義好了;
- 其二、函數(shù)內(nèi)部有可能有不同的編譯分支,有的分支有可能不會(huì)完全使用函數(shù)參數(shù)
比如上面的例子,這是一個(gè)偵聽(tīng)的接口函數(shù),BACKLOG 有可能會(huì)被裁剪掉,此時(shí)如果沒(méi)有前面的LWIP_UNUSED_ARG(backlog);,就會(huì)報(bào)backlog參數(shù)未使用的警告,如果是LWIP_TCP使能,則conn 及backlog又會(huì)報(bào)警告。
或許你會(huì)說(shuō),這有什么關(guān)系,應(yīng)該也不影響使用,是的,姑且不考慮代碼是否需要嚴(yán)格的審查。想lwip這樣一個(gè)開(kāi)源庫(kù)里,類似的地方有很多很多,如果沒(méi)有這樣的處理,使用者一編譯,哎呀,媽呀! 一堆一堆的warning! 這個(gè)開(kāi)源庫(kù)使用者的使用體驗(yàn)還會(huì)好么?如果你的應(yīng)用如果沒(méi)有編譯錯(cuò)誤還好,但凡有那么一個(gè)錯(cuò)誤,就需要在很多warning中就找那一個(gè)error! 體驗(yàn)酸爽否?
這啥原理呢?
(void) x 不會(huì)對(duì)代碼做任何額外的操作,僅僅以此來(lái)告訴編譯器不要報(bào)unused警告出來(lái)!至于是否所有編譯器是否都支持這么干,
這其實(shí)是編譯器對(duì)于unused類型的處置方式,不同的處置方式,比如:
- IAR中,如果你不做上述處置,你還可以這樣壓掉unused警告:
#pragma diag_suppress=Pe550
- 又譬如,在GCC/Clang中,也可以這么干:
int fun (__attribute__((unused)) int a)
{
return 0;
}
也或者加上-Wno-unused-parameter 編譯選項(xiàng)。
.....
不同的編譯器處置方式會(huì)略有差異,如果遇到了,知道這么回事,去查查看就知道了。如果你還需要做靜態(tài)代碼檢查,根據(jù)你使用的工具去查查文檔也會(huì)很快掌握,工具本身的方法,個(gè)人覺(jué)得在代碼中去實(shí)現(xiàn)會(huì)更好一些。
回到Hellworld
現(xiàn)在讓我們來(lái)試試void在Helloworld中的使用,加上void試試:
#include <stdio.h>
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
printf("Hello word\n");
return 0;
}
好了,今天的分享結(jié)束了,你get到這個(gè)小技巧了嗎?