知道这个电话:
pow(4);
将生成此错误消息:
error: too few arguments to function ‘pow’
我正在学习函数的指针,当看到下面的代码工作时我感到很惊讶。但为什么呢?
#include<stdio.h>
#include<math.h>
void aux(double (*function)(), double n, double x);
int main(void)
{
aux(pow, 4, 2);
aux(sqrt, 4, 0);
return 0;
}
void aux(double (*function)(double), double n, double x)
{
if(x == 0)
printf("\nsqrt(%.2f, %.2f): %f\n", n, x, (*function)(n));
else
printf("\npow(%.2f, %.2f): %f\n", n, x, (*function)(n));
}
我编译使用:
gcc -Wall -Wextra -pedantic -Wconversion -o test test.c -lm
结果是:
pow(4.00, 2.00): 16.000000
sqrt(4.00, 0.00): 2.000000
如果我将第一次调用aux
的第三个参数更改为3,则结果将更改为:
pow(4.00, 3.00): 64.000000
sqrt(4.00, 0.00): 2.000000
还有一个问题。在这种情况下,声明和使用函数指针的正确方法是什么?
答案 0 :(得分:37)
此:
void aux(double (*function)(), double n, double x);
为function
使用旧式非原型声明。空括号()
表示该函数采用固定但未指定的数字和类型的参数。
C仍然允许这种声明以实现向后兼容。 ANSI C在1989年引入了原型(指定参数类型的函数声明)。在此之前,无法在函数声明中指定参数类型,并且编译器无法检查调用是否传递了正确的数字和论证的类型。
此类声明是“过时的”,这意味着可以从未来的C标准中删除对它们的支持(但是在20多年的时间里,委员会还没有将其删除)。调用具有错误数量的参数类型的函数不一定会由编译器诊断,并且行为未定义。
当一个原型而另一个没有原型时,函数类型兼容性的规则有点复杂。这些类型:
double(double) /* function with one double parameter
returning double */
double(double, double) /* function with two double parameters
returning double */
彼此不兼容,但它们都与此类型兼容:
double() /* function with a fixed but unspecified number of parameters
returning double */
这使得在没有编译器诊断的情况下进行错误调用成为可能。
为避免此问题,始终使用原型:
void aux(double (*function)(double, double), double n, double x);
您不仅可以从编译器获得更好的诊断功能,而且不必担心非原型函数的复杂兼容性规则(如果您好奇,则会在N1570 6.7中指定。 6.3第16段。
答案 1 :(得分:9)
您的函数原型aux()
...
void aux(double (*function)(), double n, double x);
...指定第一个参数是指向返回double
并接受未指定参数的函数的指针。这可以防止GCC在main()
中针对该函数的调用发出有关不匹配类型的警告。
但是,函数aux()
的定义为其第一个参数提供了更具体的类型,该参数与您传递的实际参数不兼容。通过指针调用这些函数具有未定义的语义。几乎任何事情都可能发生,包括行为似乎是你想要的。你不能依赖任何有关这种行为的事情。
答案 2 :(得分:8)
因为您在main之前指定了aux()
的原型,而function
没有任何指定的参数类型。了解差异:
void f(); /* Accepts any number of arguments thanks to K&R C */
void g(void); /* No arguments accepted */
void h(int); /* Only one integer argument accepted */
如果您将aux()
原型声明为:
void aux(double (*function)(double), double n, double x);
海湾合作委员会开始抱怨。
答案 3 :(得分:5)
一对空括号()
告诉C编译器可以使用任何数量的参数调用该函数,但该函数本身具有特定数量的参数用于其原型。因此,如果将它与函数指针一起使用,并且传递的参数的数量和相应类型与指向函数的原型匹配,则一切都将起作用。如果你饿了参数列表或者使用不同类型的值,那么......那是未定义的行为。