代码之家  ›  专栏  ›  技术社区  ›  Sim Sun

如何理解这个定义

  •  12
  • Sim Sun  · 技术社区  · 14 年前

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

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

    我不知道什么是(int signo,void(*func)(int))。

    6 回复  |  直到 14 年前
        1
  •  24
  •   Daniel Daranas    11 年前

    一般步骤是:找到最左边的标识符并找出解决方法。缺少带括号的显式分组,后缀运算符如 () [] 在一元运算符之前绑定,如 * ;因此,以下都是正确的:

    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 . 信号 .

    你可以使用typedef使这个更容易阅读(以及 在Ubuntu linux上,linux就是这么做的);但是,我认为展示非typedef的版本来演示语法是如何工作的是很有价值的。typedef工具非常棒,但是您确实需要了解底层类型是如何工作的,以便有效地使用它。

    这个 信号

    例如,如果希望程序处理中断信号(例如从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;
    }
    

    编辑 我将示例代码扩展为 希望更能说明问题。

        2
  •  16
  •   Armen Tsirunyan    14 年前
    void (*signal(int signo, void (*func)(int)))(int);
    

    信号是接受int的函数和指向接受int并返回void的函数的指针,并返回接受int并返回void的函数指针。也就是说,

    typedef void(*funcPtr)(int)
    

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

    语法确实很奇怪,这样的事情最好用typedef来完成。例如,如果要声明一个函数,该函数接受一个int并返回一个指针,指向一个接受char并返回double的函数,则

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

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


    一。指向5个指针的数组的指针,这些指针指向每个取浮点值并返回双精度值的函数。
    2。指向3个ponter数组和4个int数组的指针
    并返回一个指向函数的指针,该函数接受一个指向函数taking int的指针,返回一个指向函数taking float and returning void的指针,并返回无符号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))
    

        3
  •  12
  •   Paul Butcher    11 年前

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

    以下是三个简单的步骤:

    [十] 或[]=>数组X大小。。。或数组未定义的大小。。。

    • =>指向。。。

    继续以螺旋/顺时针方向执行此操作,直到覆盖所有标记。

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

    “信号是一个传递int的函数,指向传递int的函数的指针不返回任何内容(void),返回指向传递int的函数的指针不返回任何内容(void)”

        4
  •  3
  •   Amarghosh    14 年前

    以防你无法访问 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
    
        5
  •  1
  •   Veivi    14 年前

    这个网站提供了对C乱语的拒绝:

    C gibberish <-> English

        6
  •  0
  •   JimR    14 年前

    安装 cdecl here

    否则,我相信阿门·茨鲁扬的回答是正确的。