C语言程序开发中的(void)size;有什么用?变量前使用(void)强制转换是什么意思?

C语言的语法极其简洁,即使是初次接触编程语言的初学者也能很快学完它的语法。不过,C语言也是一门“灵活得过了头”的编程语言,对于很多初学者来说,编写C语言程序就好像拿着一堆最基本的砖块,要修建一座大厦一样,茫然找不到方向。

奇怪的C语言代码

对于初学者来说,阅读项目源代码是学习和巩固C语言编程能力的一个好方法——从前辈们的一些优秀C语言项目中,我们能够学到很多编写程序方面的思考方式,也就是一些程序员所谓的“编程思维”,看得多了,编写C语言程序自然就手到擒来了。

不过虽然C语言的语法简单,但是我们总会看到一些令人迷惑的代码,例如下面这个函数,它来自某个开源项目,为了讨论主题,我将一些不相关的细节略去了:

void *fun(void *ud, void *ptr, int size){
    (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, int size){
    // 其他代码,未用到 ud 和 size 参数
    ...
}

在编译这段C语言代码时,编译器常常会给出下面这样的“参数未使用(unused parameter)”警告信息:

t.c: In function ‘fun’:
t.c:3:22: warning: unused parameter ‘ud’ [-Wunused-parameter]

很多C语言程序员会忽略编译器发出的警告信息,但这是非常不好的习惯,解决警告信息能够帮助我们最大程度的避免最终C语言程序出现bug。要解决“参数未使用(unused parameter)”警告信息,最直接的方法就是使用它了:

void *fun(void *ud, void *ptr, int size){
    ud;
    // 其他代码,未用到 ud 和 size 参数
    ...
}

但是编译器又会给出“C语言语句无效”的警告信息:

t.c:5:5: warning: statement with no effect [-Wunused-value]
     ud;
     ^~

为了避免出现这样的警告信息,我们当然可以对 size 和 ud 参数做一些其他操作,例如:

void *fun(void *ud, void *ptr, int size){
    ud = (void *)size;
    // 其他代码,未用到 ud 和 size 参数
    ...
}

可是这样虽然能够避免C语言编译器发出警告,但是这样会让其他阅读代码的程序员费解:“NND,ud = (void *)size;这句到底什么意思呢?”

因此,避免编译器发出参数未使用的警告信息,最好不要像上面这样操作,采用 (void) 操作更好:

void *fun(void *ud, void *ptr, int size){
    (void) ud;
    (void) size;
    // 其他代码,未用到 ud 和 size 参数
    ...
}

C语言程序员都知道 void 表示空,因此(void)ud 和(void)size 显然表示不关心 ud 和 size 的操作。这样一来,我们的意图一眼就能看出,而且还能避免编译器发出警告信息。

小结

在C语言程序开发中,定义函数时,有时会不可避免的定义一些使用不到的参数,这时编译程序时,编译器往往会发出警告信息。C语言程序员不应该忽视每一个警告信息,因此可以借助 (void)操作屏蔽掉这样的警告信息,以免更重要的编译器警告被淹没在信息流里。

阅读更多:   C语言
仅有 1 条评论
  1. Redmond

    点赞 icon_lol.gif

添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif