如何理解这个定义

时间:2010-11-08 10:25:38

标签: c linux syntax function-declaration

如今,我正在阅读APUE。我发现函数定义如下:

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

我很困惑,我知道signal是指向函数的指针,而last(int)是他的参数。 我不知道是什么(int signo,void(* func)(int))。

6 个答案:

答案 0 :(得分:24)

一般程序:找到最左边的标识符,然后解决问题。如果没有带括号的显式分组,()[]之类的后缀运算符会在*之类的一元运算符之前绑定;因此,以下都是正确的:

T *x[N]             -- x is an N-element array of pointer to T
T (*x)[N]           -- x is a pointer to an N-element array of T
T *f()              -- f is a function returning a pointer to T
T (*f)()            -- f is a pointer to a function returning T

将这些规则应用于声明,它将分解为

       signal                                      -- signal
       signal(                            )        -- is a function
       signal(    signo,                  )        -- with a parameter named signo 
       signal(int signo,                  )        --   of type int
       signal(int signo,        func      )        -- and a parameter named func
       signal(int signo,       *func      )        --   of type pointer
       signal(int signo,      (*func)(   ))        --   to a function
       signal(int signo,      (*func)(int))        --   taking an int parameter
       signal(int signo, void (*func)(int))        --   and returning void
      *signal(int signo, void (*func)(int))        -- returning a pointer
     (*signal(int signo, void (*func)(int)))(   )  -- to a function
     (*signal(int signo, void (*func)(int)))(int)  -- taking an int parameter
void (*signal(int signo, void (*func)(int)))(int); -- and returning void

简而言之,signal返回指向返回void的函数的指针。 signal有两个参数:一个整数和一个指向返回void的另一个函数的指针。

您可以使用typedef使这更容易阅读(并且Ubuntu linux上signal的手册页就是这样);但是,我认为显示非typedef类型以证明语法的工作原理是很有价值的。 typedef工具很棒,但你真的需要了解底层类型的工作原理才能有效地使用它。

signal函数设置信号处理程序;第二个参数是接收到信号时要执行的函数。返回指向当前信号处理程序(如果有)的指针。

例如,如果您希望程序处理中断信号(例如来自Ctrl-C):

static int g_interruptFlag = 0;

void interruptHandler(int sig)
{
  g_interruptFlag = 1;
}

int main(void)
{
  ...
  /**
   * Install the interrupt handler, saving the previous interrupt handler
   */
  void (*oldInterruptHandler)(int) = signal(SIGINT, interruptHandler);

  while (!g_interruptFlag)
  {
    // do something interesting until someone hits Ctrl-C
  }

  /**
   * Restore the previous interrupt handler (not necessary for this particular
   * example, but there may be cases where you want to swap out signal handlers
   * after handling a specific condition)
   */
  signal(SIGINT, oldInterruptHandler);
  return 0;
}

编辑我将signal的示例代码扩展为希望更具说明性的内容。

答案 1 :(得分:16)

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

signal是一个函数,它接受int和一个指向函数的指针,返回void并返回一个带int的函数指针并返回void。也就是说,

typedef void(*funcPtr)(int)

然后我们

funcPtr signal(int signo, funcPtr func); //equivalent to the above

语法确实很奇怪,使用typedef可以做得更好。作为一个例子,如果你想声明一个接受int的函数并返回一个指向函数的指针,并且返回double将是

double (*f(int))(char);

编辑:在评论“Wooooooow”之后,我提供了另一个更“woooow”的例子:)

让我们宣布一个带有的函数  1.指向函数的5个指针数组的指针,每个指针都浮动并返回double  2.指向3个数字阵列到4个整数阵列的指针
并返回一个指向函数的指针,该函数接受一个指向函数的指针,该函数接受int并返回指向函数的指针,该函数取浮点并返回void并返回unsigned int。

typedef解决方案是:

typedef double (*f1ptr) (float);
typedef f1ptr (*arr1ptr)[5];
typedef int (*arr2ptr)[4];
typedef arr2ptr (*arr3ptr)[3];
typedef void(*f2Ptr)(float);
typedef f2ptr (*f3ptr)(int);
typedef unsigned int (*f4ptr) (f3ptr);
f4ptr TheFunction(arr1ptr arg1, arr3ptr arg2);

现在,有趣的部分:) 没有typedef,这将是

 unsigned int (*TheFunction( double (*(*)[5])(float), int(*(*)[3])[4]))( void(*(*)(int))(float))

我的上帝,我刚刚写过吗? :)

答案 2 :(得分:12)

顺时针螺旋规则将有助于: http://c-faq.com/decl/spiral.anderson.html

  

有三个简单的步骤:

     

从未知元素开始,以螺旋/顺时针方向移动;在考虑以下元素时,用相应的英语陈述替换它们:

     

[X]或[] =>数组X大小为......或数组未定义大小......

     

(type1,type2)=>函数传递type1和type2返回...

     
      
  • =>指针... ...
  •   
     

以螺旋/顺时针方向继续这样做,直到所有标记都被覆盖。   始终先解决括号内的任何内容!

参见“示例#3:'终极'”,这正是您所要求的:

“signal是一个传递int的函数和一个传递int的函数的指针返回什么(void)返回一个指向传递int的函数的指针(void)”

答案 3 :(得分:3)

如果您目前无权访问cdecl,则此处为cdecl输出:

$ cdecl
cdecl> explain void (*signal(int , void (*)(int)))(int);
declare signal as function (int, pointer to function (int) returning void) returning pointer to function (int) returning void

答案 4 :(得分:1)

这个网站给出了C乱码的声明:

C gibberish <-> English

答案 5 :(得分:0)

为您的发布安装cdecl(如果有)或转到here

否则,我相信Armen Tsirunyan的回答是正确的。