我正在尝试在objective-c中获取块,并且正在学习指向函数的指针,因此这可能是一个非常明显的问题。我在Xcode 5中编译了以下内容并具有以下内容:
void hearThis(char * (*pFunc)(char *myString)){
/*
why does it allow me to do this? when signature for
helpMe doesn't take an argument
*/
char *str=(*pFunc)("what I want as arg");
printf("you are going to hear this: %s\n", str);
}
char * helpMe(){
return "this is from helpMe";
}
int main(){
char * (*fNewFunc)();
fNewFunc=&helpMe;
// we are passing a pointer to a function
hearThis(fNewFunc);
输出:
you are going to hear this: this is from helpMe
为什么它允许我甚至在将参数传递给不带一个OR的函数时进行编译?运行时不会崩溃?
答案 0 :(得分:3)
不带参数的函数声明的C语法是f(void)
。你的fNewFunc
是一个带有未指明参数的函数。用
char * (*fNewFunc)(void);
然后C可以至少警告你不匹配。 C ++会拒绝它。
编辑:正如chux在评论中指出的那样,char *helpMe()
定义,因为它是一个定义,确实声明helpMe
没有参数,所以没有严格的需要改变它。
答案 1 :(得分:2)
好的,我已经检查了 c99 标准,可以说这是未定义的行为。
TL; DR:可以将一个函数指针转换/转换为另一个类型,但是如果调用该函数,函数类型必须兼容,否则,你得到 undefined行为即可。您没有收到警告,因为在每个步骤中您要在兼容的函数类型之间进行转换,但最终helpMe
与pFunc
不兼容。
首先:
char *helpMe(){
return "this is from helpMe";
}
有效且在C99中与:
相同char *helpMe(void){
return "this is from helpMe";
}
来自§6.7.5.3(强调我的):
标识符列表仅声明参数的标识符 功能。 函数声明符中的空列表,它是a的一部分 该函数的定义表明该函数没有 参数即可。函数声明符中的空列表不是其中的一部分 该函数的定义指明没有关于该函数的信息 提供参数的数量或类型。
我不知道这在C89中的表现如何,我认为可能在C89中有效。
另一方面,我们有:
char * (*fNewFunc)() = helpMe;
此强制转换是有效的,因为您可以将函数指针强制转换为另一种类型的函数,并且可以毫无问题地返回。编译器不会发出警告,因为即使它们的类型兼容! (对未指定的情况无效)。
§6.3.2.3一节,第8段内容(再次强调我的):
指向一种类型的函数的指针可以转换为指向a的指针 另一种类型的功能又回来了;结果应该比较 等于原始指针。 如果使用转换的指针进行调用 一个类型与指向类型不兼容的函数 行为未定义。
因此,当您将指针传递给hearThis
时,它再次被转换,从char *(*)();
转换为char *(*)(char *);
,再次,它们与编译器兼容(因此,不会发出警告)。
但是标准说如果您调用的函数类型与指向的函数类型不兼容,则行为未定义。
现在问题是,它们是否兼容?
答案是否。如果您将fNewFunc()
的类型更改为char *(*fNewFunc)(void);
,则会收到警告:
p.c: In function ‘main’:
p.c:12:5: warning: passing argument 1 of ‘hearThis’ from incompatible pointer type [enabled by default]
p.c:6:6: note: expected ‘char * (*)(char *)’ but argument is of type ‘char * (*)(void)’
在标准中还说两种功能类型兼容。它在§6.7.5.3.15中。它有点复杂:P
可能它起作用,因为计算机不关心。它只是将参数作为寄存器推送或传递,而helpMe
只是忽略它们。但是你应该知道它是未定义的行为。