这两个声明有什么区别?

时间:2011-02-19 08:25:54

标签: c types function-pointers

这是一个简单而细腻的问题。有人可以解释a和b之间的区别吗?

void (*a)(int x, int y)
void (*b(int x, int y))(int)

这个问题来自以下Linux函数声明:

void (*signal(int sig, void (*func)(int)))(int);

解决方案

以下程序是一个很好的演示。

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void ouch(int sig)
{
   printf("OUCH! - I got signal %d\n", sig);
   signal(SIGINT, SIG_DFL);
}


void (*g())(int) // just like the b
{
   return ouch;
}

int main()
{

   void (*f)(int); // just like the a
   f=g();
   signal(SIGINT, f);

   while(1)
   {
      printf("Hello, world!\n");
      sleep(1);
   }
}

4 个答案:

答案 0 :(得分:10)

C的设计者选择以一种方式命名他们的类型,使用该类型的用例尽可能地匹配使用该类型获取值的方式。因此,例如,当你有一个像

这样的声明时
int a;

您可以说a获得int。如果您有类似

的类型
int *a;

然后,您必须通过撰写a来取消引用*a以获得int

您可以使用类似的,虽然更复杂的逻辑来解码您发布的类型。让我们从

开始
void (*a)(int x, int y)

这说明如果您取消引用a(通过撰写*a),那么您剩下的就是

void (int x, int y)

这是一个函数,它接收两个int并返回void。换句话说,您可以将a视为指向函数的指针;一旦被解除引用,你就会恢复功能。

现在这个野兽:

void (*b(int x, int y))(int)

这个比较棘手。这个想法如下。如果你取b并将两个参数传入其中,那么你会得到一些看起来像这样的东西:

void (*)(int)

指向int并返回void的函数的指针。换句话说,b是一个带有两个参数的函数,然后返回一个带有一个参数并返回void的函数指针。

解码这些类型有点棘手,所以通常你不会以这种方式编写,而是使用typedef来简化操作。例如,这个typedef:

typedef void (*FunctionTakingTwoInts)(int, int);

表示可以使用FunctionTakingTwoInts定义一个函数指针,该函数指针指向一个函数,该函数接收两个int并返回void。从这里开始,a的声明简化为

FunctionTakingTwoInts a;

同样,在b的情况下,让我们定义类型

typedef void (*FunctionTakingOneInt)(int);

现在,我们可以将b重写为

FunctionTakingOneInt b(int x, int y);

我认为,实际上这种类型的含义要清楚得多。

希望这有帮助!

答案 1 :(得分:3)

简短版本:a声明指向函数的指针。 b声明一个返回指向函数的指针的函数。

更长版本:您知道以下模式来声明指向函数的指针

void (*f)(int x, int y)

现在,取“f”,然后修改它。例如,将其设为数组

void (*f[3])(int x, int y)

现在,您没有指向函数的指针,而是有一个指向函数的指针数组。现在,如果您将其修改为函数而不是数组,则已将第一个声明转换为第二个声明

void (*f(void))(int x, int y)

您已将其修改为返回指向函数的指针的函数。您的声明不是没有像这种情况那样的参数,而是有两个参数。其中一个是int,另一个是另一个指向函数的指针。

使用typedef比组合C声明符更容易。

// your example
typedef void signal_fn(int);
signal_fn *signal(int sig, signal_fn *func);

// my example above
typedef void f_fn(int x, int y);
f_fn *f(void);

答案 2 :(得分:1)

(*a)替换为foo:

void foo(int x, int y);

a是指向类似函数的指针。

同样,将(*b(int x, int y))替换为foo:

void foo(int);

b(int x, int y)返回指向类似函数的指针。

答案 3 :(得分:0)

http://cdecl.org/可以为这样的声明提供很好的帮助。不幸的是,它不处理命名的函数参数,因此必须删除它们。喂养

  

void( signal(int,void()(int)))(int)

给出:

  

将signal声明为函数(int,指向函数的指针(int)返回void)返回指向function(int)的指针返回void