我试图在objective中找到块,并学习指向函数的指针,所以这可能是一个非常明显的问题。我在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为什么它允许我在将参数传递给在运行时不接受一个或不崩溃的函数时进行编译?
发布于 2013-12-12 19:01:59
不带参数的函数声明的C语法是f(void)。您的fNewFunc是一个接受未指定参数的函数。将其声明改为
char * (*fNewFunc)(void);然后C至少可以警告你这种错配。C++会拒绝它。
编辑:正如chux在注释中所指出的,由于char *helpMe()定义是一个定义,它确实声明helpMe不接受任何参数,因此不需要严格地更改它。
发布于 2013-12-12 19:00:16
好的,我已经检查了c99标准,可以说这是未定义的行为。
TL;DR:可以将一个函数指针转换为另一个函数类型,但是如果调用该函数,函数类型必须是兼容的,否则将得到未定义的行为。您不会收到警告,因为在每个步骤中,您都要在兼容的函数类型之间进行转换,但最终,helpMe与pFunc不兼容。
首先:
char *helpMe(){
return "this is from helpMe";
}是有效的,在C99中与以下内容相同:
char *helpMe(void){
return "this is from helpMe";
}摘自§6.7.5.3 (强调“地雷”):
identifier列表只声明函数参数的identifier。函数声明器中的一个空列表,它是该函数的definition的一部分,它说明该函数没有参数。函数声明器中的空列表不是该函数finition的defi的一部分,它不提供有关参数的数量或类型的信息。
我不知道这在C89中的表现如何,我认为也许,在C89中,这是有效的。
另一方面,我们有:
char * (*fNewFunc)() = helpMe;此转换是有效的,因为您可以将函数指针转换为另一种类型的函数,然后返回,而不会出现问题。编译器不会抛出警告,因为即使它们的类型是兼容的!(对不特定的)无效。
§6.3.2.3,第8段内容如下:
指向一种类型的函数的指针可以转换为指向另一种类型的函数的指针,然后再转换回来;结果应该与原始指针相比较。如果转换后的指针用于调用类型与指向类型不兼容的函数,则行为未定义.。
因此,当您将指针传递到hearThis时,它再次被抛出,从char *(*)();传递到char *(*)(char *);,这与编译器兼容(因此,不抛出警告)。
但是标准说,如果要调用的函数类型与所指向的函数类型不兼容,那么行为就是未定义的。
现在的问题是,它们是否兼容?
答案是NO。如果将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只是忽略它们。但是您应该知道这是未定义的行为。
https://stackoverflow.com/questions/20551643
复制相似问题