为什么函数指针声明需要知道参数和返回值的类型?

问题描述 投票:0回答:2

为什么C中的函数声明需要知道所指向函数的参数和返回值的类型?

c中的指针声明写法如下:

returnType ( *funcPtrName ) ( paramTypes )

例如下面

foo

char my_func ( int x )
{
    ...
}


int main ()
{
    char ( *foo ) ( int );

    foo = my_func;

    foo( 2 );
}

声明指向值的指针时,类型用于确定一个元素的大小(以字节为单位)。例如,在

int* p
中,
int
告诉编译器
p
指向的元素是
sizeof( int )
分开的。此信息用于指针算术。

但是,函数指针指向单个地址,并且不允许进行指针运算。

那么为什么需要额外的信息呢?包含

returnType
paramTypes
仅仅是为了支持编译器进行错误检查吗? (例如,当用户分配类型不匹配的函数时提醒用户)。

c pointers compiler-construction function-pointers static-typing
2个回答
6
投票

有几个原因。我们先考虑返回值。

假设一个程序包含代码

y = f(x);
。调用
f
后,编译器需要获取
f
返回的值并将其赋值给
y
。它从哪里获得这个值?在某些系统中,整数返回值在通用寄存器中传递,浮点返回值在浮点寄存器中传递。因此编译器无法知道返回值在哪里,除非它知道类型。宽整数,例如
long long int
,可以在多个寄存器中传递。小结构可能会在寄存器中返回,而大结构可能会在内存中返回,使用指向调用函数提供的空间的指针,并且需要将其作为隐藏参数传递给被调用函数。编译器需要知道类型才能知道要获取多少字节以及它们在哪里。

同样,编译器在调用函数时需要知道将参数放在哪里。前几个整数参数可能在通用寄存器中传递,而前几个浮点参数可能在浮点寄存器中传递。任一类型的附加参数都可能被推入堆栈。

此外,有时程序员可能会在函数实际需要浮点参数的地方传递整数表达式,例如

pow(x, 4)
中。当编译器知道参数必须是浮点参数时,它可以将其转换为期望的类型。

另一个好处是,当编译器知道类型时,如果参数与预期类型不匹配并且无法隐式转换为预期类型,它可以报告错误,如果返回类型不匹配,它也可以类似地报告错误匹配。


4
投票

是的,您所询问的“额外信息”主要是“为了支持编译器进行错误检查的目的。”

函数原型携带参数类型信息,以便编译器可以检查通过函数指针的调用是否具有被调用函数的正确参数——无论它是什么。这就是函数原型的全部要点——确保使用正确的参数调用函数。

如果你对此不感兴趣(或者如果你作弊并使用指向各种异质函数的函数指针,采用不同数量的参数,并希望一切顺利),你可以这样做——只需将括号留空,如本例所示:

#include <stdio.h>

int f1(int a, int b) { printf("f1(%d, %d)\n", a, b); }
int f2(double d) { printf("f2(%f)\n", d); }

int main()
{
    int (*allegedly_generic_function_pointer)();

    allegedly_generic_function_pointer = f1;
    (*allegedly_generic_function_pointer)(1, 2);
    allegedly_generic_function_pointer = f2;
    (*allegedly_generic_function_pointer)(3.4);
}

这里

allegedly_generic_function_pointer
是一个指向函数的指针,该函数接受未指定的参数,并返回
int
。 (“采用未指定参数的函数”是在 ANSI C 之前、函数原型发明之前描述所有函数和函数指针的方式。)如图所示,您可以使用
allegedly_generic_function_pointer
来指向(并调用)采用不同参数的函数论据。 (不过,您的编译器可能会给您各种“有用的”警告。)

到目前为止我只讨论了参数信息。所指向函数的返回类型有一个更重要的目的——因此编译器可以生成正确的代码来处理返回值。

(为什么返回类型比参数类型更重要?好吧,当您调用作用域内没有原型的函数时,编译器会假设预期参数的数量和类型与实际参数的数量和类型完全匹配在你的调用中提供 - 编译器显然知道这一点,因为在编译调用时信息就在它的前面。但是它知道被调用函数的返回类型的唯一方法是显式指定它在函数指针类型声明中。)

如果你想要一个指向带有未指定参数的函数的指针并且具有未指定的返回类型,这是你在C中根本无法做到的事情之一。(你为什么想要这样的事情?问我关于C的事情)我曾经写过一个解释器。)

© www.soinside.com 2019 - 2024. All rights reserved.