一个 C 函数声明可以有多个标识符吗?

Can a C function declaration have more than one identifier?

c-faq website 示例 3 中有一个 C 函数声明 signal

void (*signal(int, void (*fp)(int)))(int);

我想知道怎么会有两个标识符signalfp,它仍然通过编译(我在现有代码中随机添加了这一行并编译成功)?

名称fp通常用于FILE *类型的变量,但它可以用于各种其他目的(浮点、渔业保护、函数指针等)。

问题中的函数声明等同于C标准中signal()的声明,只是它在标准使用func的地方使用了fp,并且标准给出了将 sig 命名为 signal().

的第一个参数

您可以从函数声明(原型)中删除 fp;无重大变化:

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

您还可以在整个过程中为参数使用有意义的名称:

void (*signal(int signum, void (*handler)(int signum)))(int signum);

每次出现 signum 都会标识提供信号编号的位置。 signal() 的第一个参数本身是一个信号编号; handler 的参数表示将使用信号编号调用处理函数;而最外层的signum表示signal()返回的函数指针与handler的类型相同,调用时应该传递一个信号号。

另见 Understanding typedefs for function pointers in C

不,一个 C 函数 declaration/prototype 不能有一个以上的标识符。请参阅此处 cplusplus.com 上 signal 的参考页和示例代码:http://www.cplusplus.com/reference/csignal/signal/.

在此声明中:

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

我们正在声明一个名为 signal 的函数,它 return 是一个 指向 的函数 return 是 void 和接受一个 int——即:一个 指向 函数的指针,如下所示:

void func(int);

signal 函数的输入是第 1 个 int,第 2 个是指向 return 是 void 并接受 int--同样,一个 指向 函数的指针,如上面的 func。现在,在 C 语言中,当声明一个 return 是指向函数的指针并接受指向函数的指针的函数时,它看起来像 goobly-ga-gook(乱码和令人困惑的样子),这就是我们所有人的原因最初(并且经常一次又一次)看着像 signal 这样的函数声明时感到困惑。在 C 中定义像 signal 这样的函数的几个更清晰的方法,使这一切 crystal-清晰,就像这样,相反,它们都与 goobly-gook-looking 相同一:

// 1. typedef a function--call it `func_t` for "func type"
typedef void func_t(int);

// 2. Use the typedef above to define `signal`
func_t* signal(int sig, func_t* fp); // Ah, now this makes sense!

// 1. typedef a *pointer to* a function--call it `func_p` for "pointer to a func type"
typedef void (*func_p)(int);

// 2. Use the typedef above to define `signal`
func_p signal(int sig, func_p fp); // Ah, now this makes sense too!

请记住,函数中每个输入参数类型的名称 声明 在 C 中是不相关的, 甚至不必头文件和源文件之间的匹配。

例如:

my_module.h:

// Any of these 3 prototypes are equivalent, valid, and identical
// (although using sensible names which match between the header &
// source files is most clear and helpful to the reader!):
func_p signal(int sig, func_p fp);
func_p signal(int signal, func_p whatsupdude);
func_p signal(int, func_p);

my_module.c:

func_p signal(int sig, func_p fp)
{
    // define the function here
}

现在,我最初是怎么弄清楚这一切的?
答:我看了the example code from cplusplus.com。它帮助 TON 弄清楚了这一切,因为您可以看到 signal 中的 return 值如何分配给 prev_handler,这是一个指向函数的指针,您可以看到如何my_handler,定义为函数,作为第二个参数传入signal!对于踢腿,我可能还应该提到这两行是相同的,并且都是完全有效的:

prev_handler = signal (SIGINT, my_handler);
prev_handler = signal (SIGINT, &my_handler);

这是因为如果您将一个函数作为参数传入,编译器就会知道无论如何只获取它的地址。

Cplusplus example code:

/* signal example */
#include <stdio.h>      /* printf */
#include <signal.h>     /* signal, raise, sig_atomic_t */

sig_atomic_t signaled = 0;

void my_handler (int param)
{
  signaled = 1;
}

int main ()
{
  void (*prev_handler)(int);

  prev_handler = signal (SIGINT, my_handler);

  /* ... */
  raise(SIGINT);
  /* ... */

  printf ("signaled is %d.\n",signaled);


  return 0;
}

参考文献:

  1. 关于如何 typedef 函数和函数指针的提示,因为这让几乎每个人都感到困惑并且需要不时重新验证:http://www.iso-9899.info/wiki/Typedef_Function_Type