Vin*_*uda 22 c function-pointers
知道这个电话:
pow(4);
Run Code Online (Sandbox Code Playgroud)
将生成此错误消息:
error: too few arguments to function ‘pow’
Run Code Online (Sandbox Code Playgroud)
我正在学习函数的指针,当看到下面的代码工作时,我感到很惊讶.但为什么?
#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));
}
Run Code Online (Sandbox Code Playgroud)
我编译使用:
gcc -Wall -Wextra -pedantic -Wconversion -o test test.c -lm
Run Code Online (Sandbox Code Playgroud)
结果是:
pow(4.00, 2.00): 16.000000
sqrt(4.00, 0.00): 2.000000
Run Code Online (Sandbox Code Playgroud)
如果我将第一次调用的第三个参数更改aux为3,结果将更改为:
pow(4.00, 3.00): 64.000000
sqrt(4.00, 0.00): 2.000000
Run Code Online (Sandbox Code Playgroud)
还有一个问题.在这种情况下,声明和使用函数指针的正确方法是什么?
Kei*_*son 37
这个:
void aux(double (*function)(), double n, double x);
Run Code Online (Sandbox Code Playgroud)
使用旧式非原型声明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 */
Run Code Online (Sandbox Code Playgroud)
彼此不兼容,但它们都兼容此类型:
double() /* function with a fixed but unspecified number of parameters
returning double */
Run Code Online (Sandbox Code Playgroud)
这使得在没有编译器诊断的情况下进行错误调用成为可能.
要避免此问题,请始终使用原型:
void aux(double (*function)(double, double), double n, double x);
Run Code Online (Sandbox Code Playgroud)
您不仅可以从编译器获得更好的诊断,而且不必担心非原型函数的复杂兼容性规则(如果您好奇,则在N1570 6.7.6.3第16段中指定).
你的功能原型aux()......
void aux(double (*function)(), double n, double x);
Run Code Online (Sandbox Code Playgroud)
...指定第一个参数是指向返回double和接受未指定参数的函数的指针.这可以防止GCC向该函数的调用发出有关不匹配类型的警告main().
但是,函数aux()的定义为其第一个参数提供了更具体的类型,该参数与您传递的实际参数不兼容.通过指针调用这些函数具有未定义的语义.几乎任何事情都可能发生,包括行为似乎是你想要的.你不能依赖任何关于这种行为的东西.
因为您指定了aux()main之前的原型并且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 */
Run Code Online (Sandbox Code Playgroud)
如果您将aux()原型声明为:
void aux(double (*function)(double), double n, double x);
Run Code Online (Sandbox Code Playgroud)
海湾合作委员会开始抱怨.
一对空括号()告诉C编译器可以使用任意数量的参数调用该函数,但该函数本身具有其原型的特定数量的参数.因此,如果将它与函数指针一起使用,并且传递的参数的数量和相应类型与指向函数的原型匹配,则一切都将起作用.如果你饿了参数列表或使用不同类型的值,那么......那是未定义的行为.
| 归档时间: |
|
| 查看次数: |
1505 次 |
| 最近记录: |