为什么没有参数的函数可以工作,而参数为 void 的函数却不能?
Why a function with no arguments works, but a function with void as argument doesn't?
在下面的代码中,我使用 main()
外部的函数计算 PI
。两者唯一的区别是:
- 第一个代码。 我没有传递任何参数:
void calculate_pi ();
- 第二个代码。我明确表示没有要传递的参数:
calculate_pi (void);
。
我本以为第二个更好,但似乎并非如此。为什么是这样?谢谢!
第一个代码:
#include <stdio.h>
#include <stdlib.h>
void calculate_pi ();
int main(void)
{
calculate_pi ();
return 0;
}
void calculate_pi ()
{
int i, signo;
double pi_approx = 1, pi_final;
for (i = 1; i < 1000000; ++i)
{
signo = (i%2) ? -1 : 1;
pi_approx = pi_approx + (float) signo / (2*i+1);
}
pi_final = pi_approx * 4;
printf("%.10f\n", pi_final);
}
第二个代码:
#include <stdio.h>
#include <stdlib.h>
void calculate_pi (void);
int main(void)
{
calculate_pi (void);
return 0;
}
void calculate_pi (void)
{
int i, signo;
double pi_approx = 1, pi_final;
for (i = 1; i < 1000000; ++i)
{
signo = (i%2) ? -1 : 1;
pi_approx = pi_approx + (float) signo / (2*i+1);
}
pi_final = pi_approx * 4;
printf("%.10f\n", pi_final);
}
根据@KamilCuk 的评论,正确的代码应该是这样的:
#include <stdio.h>
#include <stdlib.h>
#define PI 3.14159265359
void calculate_pi (void);
int main(void)
{
calculate_pi ();
return 0;
}
void calculate_pi (void)
{
int i, signo;
double pi_approx = 1, pi_final;
for (i = 1; i < 1000000; ++i)
{
signo = (i%2) ? -1 : 1;
pi_approx = pi_approx + (float) signo / (2*i+1);
}
pi_final = pi_approx * 4;
printf("%.10f\n", pi_final);
}
在函数的 declaration/definition 处将 void
用作参数类型与在实际调用函数时用作参数之间存在差异。
void
在此上下文中只能用作参数,但不能用作函数调用中的参数。 void
类型的表达式无论如何都不能使用,因为它实际上根本不产生任何值。否则程序调用 undefined behavior.
"The (nonexistent) value of a void expression (an expression that has type void) shall not be used in anyway, and implicit or explicit conversions (except to void) shall not be applied to such an expression. If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)"
Source: C18, 6.3.2.2/1
您需要将 calculate_pi
称为 calculate_pi()
而不是 calculate_pi(void)
:
int main (void)
{
calculate_pi();
return 0;
}
"I would have thought the second one is better, but doesn't seem to be the case."
在declaration/definition处使用void
确实比使用空参数列表更好,因为带有空参数列表的声明严格来说不是原型。
C 标准状态(强调我的):
"For each different entity that an identifier designates, the identifier is visible (i.e., can be used) only within a region of program text called itsscope. Different entities designated by the same identifier either have different scopes, or are in different name spaces. There are four kinds of scopes: function,file, block, and function prototype. (A function prototype is a declaration of a function that declares the types of its parameters.)"
因此,如果您指定一个空参数列表,如 f.e,一些编译器会发出警告。 Clang 会:
"warning: this function declaration is not a prototype [-Wstrict-prototypes]"
但在这种情况下,问题出在其他地方,如上所述。
旁注:
- 如果您默认提供
void
作为参数,编译器通常会抛出错误,因此您的代码甚至不应该被编译。请考虑更换为最新且符合标准的编译器,例如 GCC 或 Clang。
声明一个带有空参数列表的函数,如 void calculate_pi();
中那样,是一种没有指定参数类型的旧 C 语法。在新代码中应该避免它。函数最好用参数列表来声明,例如 int foo(char *x);
。新语法提供了更好的类型信息并允许编译检查参数类型并提供有用的警告和错误消息。
因为 C 使用 ()
来声明没有指定参数类型的函数,所以需要不同的语法来指定一个函数有 没有 参数。根据 C 2018 6.7.6.3 10:
,使用 (void)
作为特例来表示这一点
The special case of an unnamed parameter of type void
as the only item in the list specifies that the function has no parameters.
因此,声明 void calculate_pi(void);
并不表示 calculate_pi
接受 void
参数;它说 calculate_pi
没有任何参数。这是声明没有参数的函数的首选方法。
由于该函数不接受任何参数,因此调用时应不带参数,使用 calculate_pi()
。
calculate_pi(void)
不是有效的 C 表达式。函数参数必须是值,但是void
是类型,void
类型不能作为函数参数出现。所以现代 C 中的首选代码是声明函数不带参数:
void calculate_pi(void);
并在不带参数的情况下调用它:
calculate_pi();
最好使用第一个代码,因为您已经将 return 类型的 calculae_pi() 函数指定为无效。没有必要像在第二个代码中那样输入 void。
在下面的代码中,我使用 main()
外部的函数计算 PI
。两者唯一的区别是:
- 第一个代码。 我没有传递任何参数:
void calculate_pi ();
- 第二个代码。我明确表示没有要传递的参数:
calculate_pi (void);
。
我本以为第二个更好,但似乎并非如此。为什么是这样?谢谢!
第一个代码:
#include <stdio.h>
#include <stdlib.h>
void calculate_pi ();
int main(void)
{
calculate_pi ();
return 0;
}
void calculate_pi ()
{
int i, signo;
double pi_approx = 1, pi_final;
for (i = 1; i < 1000000; ++i)
{
signo = (i%2) ? -1 : 1;
pi_approx = pi_approx + (float) signo / (2*i+1);
}
pi_final = pi_approx * 4;
printf("%.10f\n", pi_final);
}
第二个代码:
#include <stdio.h>
#include <stdlib.h>
void calculate_pi (void);
int main(void)
{
calculate_pi (void);
return 0;
}
void calculate_pi (void)
{
int i, signo;
double pi_approx = 1, pi_final;
for (i = 1; i < 1000000; ++i)
{
signo = (i%2) ? -1 : 1;
pi_approx = pi_approx + (float) signo / (2*i+1);
}
pi_final = pi_approx * 4;
printf("%.10f\n", pi_final);
}
根据@KamilCuk 的评论,正确的代码应该是这样的:
#include <stdio.h>
#include <stdlib.h>
#define PI 3.14159265359
void calculate_pi (void);
int main(void)
{
calculate_pi ();
return 0;
}
void calculate_pi (void)
{
int i, signo;
double pi_approx = 1, pi_final;
for (i = 1; i < 1000000; ++i)
{
signo = (i%2) ? -1 : 1;
pi_approx = pi_approx + (float) signo / (2*i+1);
}
pi_final = pi_approx * 4;
printf("%.10f\n", pi_final);
}
在函数的 declaration/definition 处将 void
用作参数类型与在实际调用函数时用作参数之间存在差异。
void
在此上下文中只能用作参数,但不能用作函数调用中的参数。 void
类型的表达式无论如何都不能使用,因为它实际上根本不产生任何值。否则程序调用 undefined behavior.
"The (nonexistent) value of a void expression (an expression that has type void) shall not be used in anyway, and implicit or explicit conversions (except to void) shall not be applied to such an expression. If an expression of any other type is evaluated as a void expression, its value or designator is discarded. (A void expression is evaluated for its side effects.)"
Source: C18, 6.3.2.2/1
您需要将 calculate_pi
称为 calculate_pi()
而不是 calculate_pi(void)
:
int main (void)
{
calculate_pi();
return 0;
}
"I would have thought the second one is better, but doesn't seem to be the case."
在declaration/definition处使用void
确实比使用空参数列表更好,因为带有空参数列表的声明严格来说不是原型。
C 标准状态(强调我的):
"For each different entity that an identifier designates, the identifier is visible (i.e., can be used) only within a region of program text called itsscope. Different entities designated by the same identifier either have different scopes, or are in different name spaces. There are four kinds of scopes: function,file, block, and function prototype. (A function prototype is a declaration of a function that declares the types of its parameters.)"
因此,如果您指定一个空参数列表,如 f.e,一些编译器会发出警告。 Clang 会:
"warning: this function declaration is not a prototype [-Wstrict-prototypes]"
但在这种情况下,问题出在其他地方,如上所述。
旁注:
- 如果您默认提供
void
作为参数,编译器通常会抛出错误,因此您的代码甚至不应该被编译。请考虑更换为最新且符合标准的编译器,例如 GCC 或 Clang。
声明一个带有空参数列表的函数,如 void calculate_pi();
中那样,是一种没有指定参数类型的旧 C 语法。在新代码中应该避免它。函数最好用参数列表来声明,例如 int foo(char *x);
。新语法提供了更好的类型信息并允许编译检查参数类型并提供有用的警告和错误消息。
因为 C 使用 ()
来声明没有指定参数类型的函数,所以需要不同的语法来指定一个函数有 没有 参数。根据 C 2018 6.7.6.3 10:
(void)
作为特例来表示这一点
The special case of an unnamed parameter of type
void
as the only item in the list specifies that the function has no parameters.
因此,声明 void calculate_pi(void);
并不表示 calculate_pi
接受 void
参数;它说 calculate_pi
没有任何参数。这是声明没有参数的函数的首选方法。
由于该函数不接受任何参数,因此调用时应不带参数,使用 calculate_pi()
。
calculate_pi(void)
不是有效的 C 表达式。函数参数必须是值,但是void
是类型,void
类型不能作为函数参数出现。所以现代 C 中的首选代码是声明函数不带参数:
void calculate_pi(void);
并在不带参数的情况下调用它:
calculate_pi();
最好使用第一个代码,因为您已经将 return 类型的 calculae_pi() 函数指定为无效。没有必要像在第二个代码中那样输入 void。