不要将函数的参数列表留空使用 void

假设你正在创建一个在调用时不需要参数的函数,并且你面临着如何在函数原型和函数定义中定义参数列表的困境。

  • 你可以选择将原型和定义的参数列表保持为空。因此,它们看起来就像你需要的函数调用语句。

  • 你在某处读到关键字 void (只有少数几个)的使用之一,就是定义不接受调用中任何参数的函数的参数列表。所以,这也是一个选择。

那么,哪个是正确的选择呢?

答案: 使用关键字 void

一般建议: 如果某种语言提供某些特殊功能,你最好在代码中使用它。例如,使用 enums 而不是 #define 宏(这是另一个例子)。

C11 第 6.7.6.3 节函数声明者第 10 段规定:

void 类型的未命名参数作为列表中唯一项的特殊情况指定该函数没有参数。

同一节的第 14 段显示了唯一的区别:

…函数声明符中的空列表是该函数定义的一部分,指定该函数没有参数。函数声明符中的空列表不是该函数定义的一部分,它指定不提供有关参数数量或类型的信息。

K&R(pgs-72-73)为上述内容提供的简化说明:

此外,如果一个函数声明不包含参数,就像在
double atof(); 中那样,那也意味着没有任何关于 atof 的参数的假设; 所有参数检查都已关闭。空参数列表的这种特殊含义旨在允许较旧的 C 程序使用新的编译器进行编译。但是将它与新程序一起使用是一个坏主意。如果函数接受参数,则声明它们; 如果不参数,请使用 void

这就是你的函数原型应该是这样的:

int foo(void);

这就是函数定义的方式:

int foo(void)
{
    ...
    <statements>
    ...
    return 1;
}

使用上面的 int foo() 类型声明(即不使用关键字 void )的一个优点是,如果使用像 foo(42) 这样的错误语句调用函数,编译器可以检测到错误。如果将参数列表留空,则此类函数调用语句不会导致任何错误。错误将无声地传递,未检测到,代码仍将执行。

这也意味着你应该像这样定义 main() 函数:

int main(void)
{
    ...
    <statements>
    ...
    return 0;
}

请注意,即使使用空参数列表定义的函数不带参数,它也不会为函数提供原型,因此如果随后使用参数调用函数,编译器将不会抱怨。例如:

#include <stdio.h>

static void parameterless()
{
    printf("%s called\n", __func__);
}

int main(void)
{
    parameterless(3, "arguments", "provided");
    return 0;
}

如果该代码保存在文件 proto79.c 中,则可以在 Unix 上使用 GCC(用于演示的 macOS Sierra 10.12.5 上的 7.1.0 版)进行编译,如下所示:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -pedantic proto79.c -o proto79
$

如果使用更严格的选项进行编译,则会出现错误:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -pedantic proto79.c -o proto79 
proto79.c:3:13: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
 static void parameterless()
             ^~~~~~~~~~~~~
proto79.c: In function ‘parameterless’:
proto79.c:3:13: error: old-style function definition [-Werror=old-style-definition]
cc1: all warnings being treated as errors
$

如果你给函数正式原型 static void parameterless(void),那么编译会给出错误:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -pedantic proto79.c -o proto79 
proto79.c: In function ‘main’:
proto79.c:10:5: error: too many arguments to function ‘parameterless’
     parameterless(3, "arguments", "provided");
     ^~~~~~~~~~~~~
proto79.c:3:13: note: declared here
 static void parameterless(void)
             ^~~~~~~~~~~~~
$

道德 - 始终确保你拥有原型,并确保你的编译器在你不遵守规则时告诉你。