一个 C 函数声明可以有多个标识符吗?
Can a C function declaration have more than one identifier?
c-faq website 示例 3 中有一个 C 函数声明 signal
:
void (*signal(int, void (*fp)(int)))(int);
我想知道怎么会有两个标识符signal
,fp
,它仍然通过编译(我在现有代码中随机添加了这一行并编译成功)?
名称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);
这是因为如果您将一个函数作为参数传入,编译器就会知道无论如何只获取它的地址。
/* 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;
}
参考文献:
- 关于如何 typedef 函数和函数指针的提示,因为这让几乎每个人都感到困惑并且需要不时重新验证:http://www.iso-9899.info/wiki/Typedef_Function_Type
c-faq website 示例 3 中有一个 C 函数声明 signal
:
void (*signal(int, void (*fp)(int)))(int);
我想知道怎么会有两个标识符signal
,fp
,它仍然通过编译(我在现有代码中随机添加了这一行并编译成功)?
名称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);
这是因为如果您将一个函数作为参数传入,编译器就会知道无论如何只获取它的地址。
/* 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;
}
参考文献:
- 关于如何 typedef 函数和函数指针的提示,因为这让几乎每个人都感到困惑并且需要不时重新验证:http://www.iso-9899.info/wiki/Typedef_Function_Type