指向函数赋值的指针,C

时间:2011-09-01 16:53:08

标签: c pointers function-pointers

我不明白为什么以下代码会生成警告:

int func(double a, int b, char c)
{
    return 0;
}
int main()
{
    int(*myPointer)() = func;
    return 0;
}

我认为在C中,具有空参数列表的函数意味着可以接收未知数量的参数的函数。 func4恰好接收3个参数。那为什么它与myPointer不兼容?

它特别令人困惑,因为以下编译时没有警告:

void boo()
{
     return;
}
int main()
{
    int(*pointerDude)(double) = boo;
    return 0;
}

发生了什么事?

6 个答案:

答案 0 :(得分:1)

这两种情况之间的区别如下:如果将参数传递给不接受任何参数的函数,则只是在堆栈上消耗了一些内存。如果你没有将任何参数传递给接受一些参数的函数,后者将从堆栈中读取随机数据。

更新:更改为社区维基以从Pascal Cuoq添加这些更正:

两个方向上的函数指针的转换都是合法的,尽管来自编译器的信息性警告。在两种情况下,使用错误的原型调用函数都是非法的。一些ABI要求函数清理堆栈,在这种情况下,将参数传递给不接受的函数会破坏堆栈,因为不会将参数传递给期望它们的函数。

C99 6.3.2.3 par。 8:

  

指向一种类型的函数的指针可以转换为指向a的指针   另一种类型的功能又回来了;结果应该比较   等于原始指针。如果转换的指针用于调用   一个类型与指向类型不兼容的函数   行为未定义

答案 1 :(得分:0)

IIRC C编译器有一定的假设可能导致非常奇怪的错误,因为你没有告诉它在调用该函数时需要多少堆栈空间。特别是因为定义不匹配,这可能允许某人无意中读取您的函数指针声明并假设没有参数并使函数返回垃圾。如果你真的想采用可变数量的参数,请使用my_func(...)和varargs。

答案 2 :(得分:0)

警告只是一个警告。诚实。

在这种情况下,编译器知道你有一个不正确的函数指针类型,它公然告诉你。如果您尝试传递一些不同于3的参数,那么它将发出错误。

答案 3 :(得分:0)

我认为问题与参数的转换有关,因为char不是32位。请注意,如果将char更改为int,则可以正常工作。它与自动推广变量有关。

比较两者:

int func();
int func(double a, int b, int c) 
{
    return 0;
}

int func();
int func(double a, int b, char c) 
{
    return 0;
}

gcc为您提供第二个警告,但不是第一个

答案 4 :(得分:0)

这是你得到的警告:

  

警告:从不兼容的指针类型初始化

您正在传递void,这意味着需要演员。你应该使用正确的类型。

答案 5 :(得分:-1)

在C中,空参数列表表示该函数不接受任何参数。我相信你把一个空的参数列表与varargs混淆了。

更改第一个示例以包含参数将删除警告。

int func(double a, int b, char c)
{
    return 0;
}
int main()
{
    int(*myPointer)(double, int, char) = func;
    return 0;
}