【问题标题】:Can a C function declaration have more than one identifier?C 函数声明可以有多个标识符吗?
【发布时间】:2020-02-24 03:50:07
【问题描述】:

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

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

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

【问题讨论】:

标签: c signals function-pointers typedef


【解决方案1】:

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

问题中的函数声明等同于C标准中signal()的声明,只是它使用fp,而标准使用func,标准将名称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的类型相同,调用时应该(is)传递一个信号号。

另见Understanding typedefs for function pointers in C

【讨论】:

    【解决方案2】:

    不,C 函数声明/原型不能有多个标识符。请参考 cplusplus.com 上 signal 的参考页面和示例代码:http://www.cplusplus.com/reference/csignal/signal/

    在此声明中:

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

    我们声明了一个名为signal 的函数,它返回一个指向的函数,该函数返回void 并接受一个int——即:一个指向 一个这样的函数:

    void func(int);
    

    signal 函数的输入是第一个,int,第二个,一个指向函数的指针,该函数返回一个 void 并接受一个 int--再次,一个 指向 像上面的func 这样的函数。现在,在 C 语言中,当声明一个返回指向函数的指针并接受指向函数的指针的函数时,它看起来都像 goobly-ga-gook-looking(乱码和令人困惑的外观),这就是为什么我们最初都会感到困惑(一次又一次地)查看像signal这样的函数声明。在 C 中定义像 signal 这样的函数的几个更清晰的方法,使这一切都变得一目了然,就像这样,相反,这两种方法都与 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 的返回值是如何分配给 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. 提醒一下如何对函数和函数指针进行类型定义,因为这会让几乎每个人都感到困惑,并且需要不时重新验证:http://www.iso-9899.info/wiki/Typedef_Function_Type

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-27
      • 1970-01-01
      • 2012-11-13
      • 1970-01-01
      相关资源
      最近更新 更多