函数指针声明

3
  1. 使用typedef声明函数指针,应该像这样:

    typedef void (*FOO)(int i)

    但通常typedef的语法是这样的:

    typedef int BOOL

    为什么第一个不是这样呢:

    typedef void (*)(int) FOO

  2. 返回函数指针(不使用typedef)的语法如下:

    void (*foo(char c))(int)

    这意味着foo接收一个字符,并返回一个指向接收一个整数并返回空值的函数的指针。这个语法看起来非常奇怪!它看起来像foo接收一个整数并返回空值。括号似乎没有放在正确的位置。如果要返回函数指针,为什么不像这样:

    (void (*)(int)) foo(char c)

    这个很直观。我真的很难理解这里的语法,更不用说使用它了。有人能请解释一下这里发生了什么吗?


1
它就是它本身。你的问题确切是什么?你似乎已经理解了所有这些工作原理。 - David Heffernan
当您声明一个整数时,在“int”之后写下名称。在声明函数时,名称位于返回类型和参数之间。同样在这里,名称不是在整个内容之后,而是在中间。而且,名称不是foo,而是foo(...) - deviantfan
有些声明(如函数指针和数组typedefs/数组指针参数)必须从内部向外读取。你观察到这与其他类型的typedef略有不同是正确的。在我看来,没有人喜欢这种语法,现代语言也放弃了类似的语法(例如C#中的委托/数组声明)。在我看来,在函数/数组指针的情况下,始终使用typedef。如果您从函数返回funcptr或将funcptr作为参数传递,则使用另一个funcptr的typedef声明返回值和/或函数参数,以编写可读的代码。 - pasztorpisti
1
@WhozCraig:我已经做了10年的C++,是的,这总是让我恼火。 - Mooing Duck
1
这对我来说也一直很反常,有时我仍然需要查找...我觉得你在这里得到的回应有点奇怪。 - Grady Player
显示剩余2条评论
3个回答

4
一个整数就是:
int x;

以上的名称为:

typedef int x_type;

一个指向 int 的指针是:
int *p;

它的类型将是:
typedef int *p_type;

一个名为foo的函数,它接收一个double类型参数并返回一个int类型结果,其定义为:
int foo(double);

foo的类型定义为:

typedef int foo_type(double);

现在,指向上述内容的指针应该带一个*,但是()(函数调用)比*(解引用)更紧密地绑定,因此需要加括号:
typedef int (*ptr_to_foo_type)(double);

这段内容可能更好地表达为:
typedef foo_type *ptr_to_foo_type;

有些人建议要写得更加清晰易懂。

这个想法是让类型描述看起来(有点)像它的使用方式。大多数人都认为前缀/后缀运算符会搞砸这个想法。但现在改变已经太晚了。


2
声明语法基于表达式类型,而不是对象类型。另一种说法是,“声明模仿使用”。
让我们从一个简单的指针表达式开始;称之为iptr。 iptr指向一个整数值。 如果我们想要访问该值,我们需要使用一元*运算符对iptr进行解引用,像这样:
x = *iptr;

表达式 *iptr 的类型为 int,因此声明 iptr 的语法如下:

int *iptr;

如果您想为一个 int 指针创建一个 typedef,您需要添加 typedef 来实现。

typedef int *iptr;

iptr现在作为类型“指向int的指针”的同义词,所以您可以编写:

iptr ip;

该语句将 ip 声明为指向 int 的指针(通常情况下,您真的不想在 typedef 中隐藏指针)。

现在假设您有一个指向接受两个 int 参数并返回 int 值的函数的指针,称其为 fp。要调用该函数,您需要解引用指针并将必要的参数传递给结果函数,如下所示:

x = (*fp)(arg1, arg2);  // C allows you to omit the * in the call, so you could
                        // also write it as simply x = fp(arg1, arg2), but we're
                        // leaving it in so the following explanation makes sense

函数调用()运算符的优先级高于一元*; *fp()将被解释为*(fp()),这不是我们想要的。为了在调用它指向的函数之前取消引用fp,我们必须显式地将*运算符与fp分组。
表达式(*fp)(arg1, arg2)的类型为int,因此fp的声明变为:
int (*fp)(int arg1, int arg2);

现在让我们看一下你的第二个例子:foo 是一个函数,它接受一个 char 参数,并返回一个指向一个接受 int 参数并返回 void 的函数的指针。你可以像这样调用它:

(*foo(c))(x);

再次强调,表达式 (*foo(c))(x) 的类型为 void,因此声明应该是

void (*foo(char c))(int x);

为了语法上的原因,typedef被视为存储类说明符,就像externstatic一样,尽管它有非常不同的含义。它不会改变声明的结构;它只是改变了编译器如何解释该声明的方式。将typedef添加到上面的内容中,如下所示:
typedef void (*foo(char c))(int x);

现在创建了同义词foo,用于表示返回指向返回void的函数指针的函数类型。这与更简单的类型定义没有区别,例如:
typedef int *iptr;

表现良好。

0

1)typedef的语法是在该类型的变量声明前面加上typedef

2)声明的语法反映了实际获取该类型值的语法。请参阅我的其他最近的答案,涉及地址运算符(包括函数调用)的优先级,例如(*twod)[3] vs *(twod)[3] C Pointers ... 我不想再重复一遍了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接