我有一个简短的程序,我将用它来测试“无限递归”。但是,我遇到了另一个与函数指针相关的棘手问题......
该计划如下:
#include <stdio.h>
int repeat(char (*func)(int, int), int a) {
func(a, a+1);
return repeat(func, a+1);
}
char f (int a , int b){
printf("%d\n", a);
//return (double)(a + b);
return 'c';
}
int main(int argc, char const *argv[])
{
repeat(&f, 1);
return 0;
}
至于我,我认为“重复(&amp; f,1)”中的'f'具有“ char * ”的类型和'func' 'in“ int repeat(char(* func)(int,int),int a)”的类型为“ char * ”。
然而,这似乎很奇怪。如果我改变“(char(* func)(int,int),int a)”to “(char func(int,int),int a)”,编译器(在gcc和vc6中测试)不会发出任何警告,并且运行结果是相同的。
如果我改变“(char(* func)(int,int),int a)”to“(double func(int,int),int a)“, 编译器抛出:
警告:不兼容的指针类型将'char()(int,int)'传递给'double()(int,int)'类型的参数'[-Wincompatible-pointer-types ]重复(&amp; f,1);
似乎编译器将“ double(int,int)”和“ double(*)(int,int)”视为相同的东西。换句话说,如果我将“(char(* func)(int,int),int a)”更改为“ double(* func)(int,int) “,编译器将抛出相同的消息(我已经测试过了):
警告:不兼容的指针类型将'char()(int,int)'传递给'double()(int,int)'类型的参数'[-Wincompatible-pointer-types ]重复(&amp; f,1);
神... 好吧,这不是结束。 之后,我将“重复(&amp; f,1)”更改为“重复(f,1)”,其他部分保持不变。 也就是说,整个程序是:
#include <stdio.h>
int repeat(char (*func)(int, int), int a) {
func(a, a+1);
return repeat(func, a+1);
}
char f (int a , int b){
printf("%d\n", a);
//return (double)(a + b);
return 'c';
}
int main(int argc, char const *argv[])
{
repeat(f, 1);
return 0;
}
编译器不提供任何警告,并且运行结果是相同的。
所以我很困惑,所有以下巴黎都不会产生任何警告和正确的结果。
1 repeat(&f, 1) int repeat(char (*func)(int, int), int a)
2 repeat(&f, 1) int repeat(char func(int, int), int a)
3 repeat(f, 1) int repeat(char (*func)(int, int), int a)
4 repeat(f, 1) int repeat(char func(int, int), int a)
当然“重复(f,1)”中的'f'的类型为“ char(int,int)”和'func'在“ int repeat(double( func)(int,int),int a) ”的类型为“ char( )(int,int)“。
你可以通过改变“ int repeat(char(* func)(int,int),int a)”到“ int repeat(double(* func)(int) ,int),int a)“并检查警告信息:
警告:不兼容的指针类型将'char(int,int)'传递给'double()(int,int)'的参数'[-Wincompatible-pointer-types] repeat(f, 1); *
谁可以发表评论?我完全认为只有四个中的第一个在类型方面是正确的。
答案 0 :(得分:3)
当用作函数参数时,两种语法
foo(char bar(int, int), int a)
和
foo(char (*bar)(int, int), int a)
从编译器的角度来看是相同的。
另请注意,当您调用函数foo
时,传递给它的函数的名称将被视为指向该函数的指针。这两个调用都是有效的
foo(&f, 1)
foo(f, 1)
至于我,我认为
f
中的repeat(&f, 1)
类型为char *
,而func
中的int repeat(char (*func)(int, int), int a)
类型为char *
}},太。
不。 f
和func
都属于char (*)(int, int)
类型,即它们是 指向函数的指针,该函数将两个int
作为参数并返回{{1} }
答案 1 :(得分:1)
参数类型:
()
在语法:
int repeat(char (*func)(int, int), int a)
表示(*func)(int,int)
是一个函数,它接受两个int
个参数并返回char
。 *
表示func
指向返回char
的函数的指针。
以下更现代的语法也可以起作用:
int repeat(char func(int, int), int a)
注意,以下内容看起来接近第一个,但是完全不同,函数参数将是指向返回char *
的函数的指针:
int repeat(char *func(int, int), int a)
是的,仅仅为了完整性,int repeat((char *)func(int, int), int a)
将是语法错误,因为(char*)
将被理解为强制转换操作符,而类型是预期的。
使用f和&amp; f语法:
C11标准部分6.5.3.2声明“一元&
运算符产生其操作数的地址。如果操作数的类型为''type'',则结果有类型''指向类型''“的指针:
f
是一个函数,将两个int
作为参数并返回char
&f
是指向函数的指针,该函数将两个int
作为参数并返回char
。 但是6.3.2.1/4节中的标准还指出“一个函数指示符是一个具有函数类型的表达式。(...)一个函数指示符,其类型为''函数返回类型''被转换到一个表达式,其类型为''指向函数返回类型的指针''“:
f
是一个函数,将两个int
作为参数并返回char
f
也被理解为指向函数的指针,该函数将两个int
作为参数并返回{{1} }。 如今,你会发现两种语法。
从历史上看,以前在char
语法中使用*
是强制调用指向的函数(参见原始K&amp; R)。