去除warning的一个骚操作~

你是否被要求写的代码需要0 erros, 0 warnings? 或者你的项目是否需要做静态代码检测?0 erros一定要做到,而0 wanring有时候会让你抓狂。前面转了一篇数组内包含头文件的写法,看起来对此类不太常见的写法大家比较感兴趣,今天来分享一个去除函数参数未使用warning的技巧。使用void即可轻松去除,如果你知道怎么用,可以关闭此文了,因为很简单没用过的则可以学习学习。

先举个栗子

看一个都熟悉经典栗子:

#include <stdio.h>
int main(int argc, char *argv[])
{
    printf("Hello World\n");
    return 0;
}

这程序简单吧?不能再简单了!编译运行正常,看到了Hello World,编译也没有错:

But,却有两个warning! 嗯?这样一个沙雕代码,管它是否warning!没错,这里确实可以不去管。可是如果你做一些特殊行业的嵌入式开发,比如汽车、医疗、工控、军工等,其代码都可能要求做静态代码检测,如果你函数中的参数没被使用,就一定会抛出这样的警告!要求严格的企业,这样的代码是不可以提交的,比如工业做IEC61508功能安全认证,代码是需要提交给认证机构审查的,这样带warning的,你还想拿证吗?同样在医疗、汽车领域,则要求就更为严谨了,就更遑论军工了。

那么怎么整呢?

且看lwip的做法

在\src\include\lwip\Arch.h中定义了这样一个宏:

#ifndef LWIP_UNUSED_ARG
#define LWIP_UNUSED_ARG(x) (void)x
#endif /* LWIP_UNUSED_ARG */ 

让我们来随便搜一个使用的地方:

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 */
}

你看,这个函数里有三处使用这个宏?细心的童鞋可能会说,既然不用函数参数原型把它干掉不就好了吗?这里有两个原因:

  • 其一、有的参数在开发中可能是预留接口,项目是不断迭代开发的,有些功能可能刚开始没做,但是接口有可能提前定义好了;
  • 其二、函数内部有可能有不同的编译分支,有的分支有可能不会完全使用函数参数

比如上面的例子,这是一个侦听的接口函数,BACKLOG 有可能会被裁剪掉,此时如果没有前面的LWIP_UNUSED_ARG(backlog);,就会报backlog参数未使用的警告,如果是LWIP_TCP使能,则conn 及backlog又会报警告。

或许你会说,这有什么关系,应该也不影响使用,是的,姑且不考虑代码是否需要严格的审查。想lwip这样一个开源库里,类似的地方有很多很多,如果没有这样的处理,使用者一编译,哎呀,妈呀! 一堆一堆的warning! 这个开源库使用者的使用体验还会好么?如果你的应用如果没有编译错误还好,但凡有那么一个错误,就需要在很多warning中就找那一个error! 体验酸爽否?

这啥原理呢?

(void) x 不会对代码做任何额外的操作,仅仅以此来告诉编译器不要报unused警告出来!至于是否所有编译器是否都支持这么干,

这其实是编译器对于unused类型的处置方式,不同的处置方式,比如:

  • IAR中,如果你不做上述处置,你还可以这样压掉unused警告:
#pragma diag_suppress=Pe550
  • 又譬如,在GCC/Clang中,也可以这么干:
int fun (__attribute__((unused)) int a) 
{
   return 0;
}

也或者加上-Wno-unused-parameter 编译选项。

.....

不同的编译器处置方式会略有差异,如果遇到了,知道这么回事,去查查看就知道了。如果你还需要做静态代码检查,根据你使用的工具去查查文档也会很快掌握,工具本身的方法,个人觉得在代码中去实现会更好一些。

回到Hellworld

现在让我们来试试void在Helloworld中的使用,加上void试试:

#include <stdio.h>
int main(int argc, char *argv[])
{
    (void)argc;
    (void)argv;
    printf("Hello word\n");
    return 0;
}

好了,今天的分享结束了,你get到这个小技巧了吗?

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 1
收藏 2
关注 75
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧