12

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

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

我很困惑,我知道信号是指向函数的指针,最后一个(int)是他的参数。我不知道什么是 (int signo,void (*func)(int))。

4

6 回答 6

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返回一个指向返回函数的指针voidsignal接受两个参数:一个整数和一个指向另一个返回的函数的指针void

您可以使用 typedefs 使其更易于阅读(signalUbuntu linux 上的手册页就是这样做的);但是,我认为展示非 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希望更具说明性的内容。

于 2010-11-08T12:23:52.413 回答
16
void (*signal(int signo, void (*func)(int)))(int);

signal 是一个函数,它接受 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);

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

让我们声明一个函数,它需要
1. 一个指向数组的指针,该数组由 5 个指向函数的指针组成,每个函数采用浮点数并返回双精度数。
2. 一个指向 3 个指针的数组的指针,指向 4 个 int 的数组,
并返回一个指向函数的指针,该指针接受一个指向函数的指针,该指针采用 int 并返回一个指向函数的指针,该指针采用 float 并返回 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))

我的天,我刚刚写的吗?:)

于 2010-11-08T10:33:55.720 回答
12

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

需要遵循三个简单的步骤:

从未知元素开始,沿螺旋/顺时针方向移动;当遇到以下元素时,用相应的英文语句替换它们:

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

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

  • => 指向...的指针

继续以螺旋/顺时针方向执行此操作,直到所有标记都被覆盖。始终首先解决括号中的任何内容!

请参阅“示例 #3:‘终极’”,这几乎正是您所要求的:

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

于 2010-11-08T10:36:05.143 回答
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
于 2010-11-08T10:50:27.473 回答
1

该网站对 C 胡言乱语给予了谴责:

C 胡言乱语 <-> 英语

于 2010-11-08T10:50:10.910 回答
0

为您的发行版安装cdecl(如果可用)或转到此处

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

于 2010-11-08T10:40:04.607 回答