C语言的语法极其简洁,即使是初次接触编程语言的初学者也能很快学完它的语法。不过,C语言也是一门“灵活得过了头”的编程语言,对于很多初学者来说,编写C语言程序就好像拿着一堆最基本的砖块,要修建一座大厦一样,茫然找不到方向。
茫然找不到方向奇怪的C语言代码
对于初学者来说,阅读项目源代码是学习和巩固C语言编程能力的一个好方法——从前辈们的一些优秀C语言项目中,我们能够学到很多编写程序方面的思考方式,也就是一些程序员所谓的“编程思维”,看得多了,编写C语言程序自然就手到擒来了。
不过虽然C语言的语法简单,但是我们总会看到一些令人迷惑的代码,例如下面这个函数,它来自某个开源项目,为了讨论主题,我将一些不相关的细节略去了:
void*fun(void*ud,void*ptr,intsize){
(void)ud;
(void)size;
//其他代码,未用到ud和size参数
...
}
fun()函数中省略掉的代码没有使用到ud和size参数,这里有两个问题:一是既然用不到这两个参数,为什么不删去它们呢?再就是两个参数前的(void)类型转换有什么用呢?
为什么不删除多余参数呢?首先考虑第一个问题
前文提到fun()函数来自一个C语言程序开源项目,该项目比较复杂,但是我们知道再复杂的程序项目也是一行一行代码敲出来的,而且,在后续的开发中,可能会修改之前的设计。明白这一点,要回答第一个问题就简单了。
可能在之前的设计中,fun()函数是用到了ud和size参数的,只是后来的设计发现fun()函数不必使用这两个参数,但是发现整个C语言项目由大量使用fun()函数的代码。
如果删去这两个参数,那么fun()函数的原型就改变了,开发人员将不得不逐个修改整个C语言项目中所有调用fun()函数的代码,这样的工作量巨大,极其容易给C语言项目引入bug。因此,倒不如继续保留fun()函数的原型不变了。
另外,读者应该已经知道C语言是不支持重载的,因为如果该C语言项目需要使用fun()函数对接某些API,那么fun()函数就必须符合API指定的原型,因此fun()函数中有未使用的参数其实是“身不由己”的。
“身不由己”还有一种情况,fun()函数可能是某个“函数家族”里的一个,该“函数家族”由一个统一的函数指针管理(为了方便,以及提高效率,实例可参考我之前文章。),因为“统一的函数指针”类型是固定的,所以fun()函数的原型必须符合该函数指针的原型,所以,即使fun()函数用不到ud和size参数,也是不能将其删除的,否则就无法通过“统一的函数指针”调用fun()函数了。
当然了,也有可能纯粹是因为开发人员懒得修改fun()函数原型。现在明白了第一个问题,再来考虑第二个问题。
为什么要在未使用的参数前添加(void)呢?
在解答这个问题之前,我们先做一个实验:编写下面这段C语言代码,也即删去(void)ud和(void)size:
void*fun(void*ud,void*ptr,intsize){
//其他代码,未用到ud和size参数
...
}
在编译这段C语言代码时,编译器常常会给出下面这样的“参数未使用(unusedparameter)”警告信息:
t.c:Infunction‘fun’:t.c:3:22:warning:unusedparameter‘ud’[-Wunused-parameter]
忽略编译器发出的警告信息,是非常不好很多C语言程序员会忽略编译器发出的警告信息,但这是非常不好的习惯,解决警告信息能够帮助我们最大程度地避免最终C语言程序出现bug。要解决“参数未使用(unusedparameter)”警告信息,最直接的方法就是使用它了:
void*fun(void*ud,void*ptr,intsize){
ud;
//其他代码,未用到ud和size参数
...
}
但是编译器又会给出“C语言语句无效”的警告信息:
t.c:5:5:warning:statementwithnoeffect[-Wunused-value]
ud;^~
为了避免出现这样的警告信息,我们当然可以对size和ud参数做一些其他操作,例如:
void*fun(void*ud,void*ptr,intsize){
ud=(void*)size;
//其他代码,未用到ud和size参数
...
}
可是这样虽然能够避免C语言编译器发出警告,但是这样会让其他阅读代码的程序员费解:“NND,ud=(void*)size;这句到底什么意思呢?”
因此,避免编译器发出参数未使用的警告信息,最好不要像上面这样操作,采用(void)操作更好:
void*fun(void*ud,void*ptr,intsize){
(void)ud;(void)size;
//其他代码,未用到ud和size参数
...
}
C语言程序员都知道void表示空,因此(void)ud和(void)size显然表示不关心ud和size的操作。这样一来,我们的意图一眼就能看出,而且还能避免编译器发出警告信息。
小结
在C语言程序开发中,定义函数时,有时会不可避免的定义一些使用不到的参数,这时编译程序时,编译器往往会发出警告信息。C语言程序员不应该忽视每一个警告信息,因此可以借助(void)操作屏蔽掉这样的警告信息,以免更重要的编译器警告被淹没在信息流里。
点个赞再走吧欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就