维基百科文章中的函数指针声明

Function pointer decleration in Wikipedia article

在维基百科关于 typedef 的文章中,有以下关于将 typedef 用于函数指针的示例:

typedef void (*sighandler_t)(int);

sighandler_t signal(int sig, sighandler_t func);

也许因为我是C的新手,这让我感到困惑:sighandler_t是一个指向带有1个int参数的函数的指针,如何在下一行用一个int +另一个函数指针来声明信号? 感谢您的帮助!

文章:https://en.wikipedia.org/wiki/Typedef

函数signal有自己的类型

sighandler_t (int sig, sighandler_t func)

或者写成函数指针 then

sighandler_t ( * )(int sig, sighandler_t func)

是它的return类型,第二个参数类型是函数指针类型sighandler_t

那是函数 signal returns 指向类型 sighandler_t 的函数的指针并且有两个参数:第一个类型 intsighandler_t.

类型的第二个

没有 typedef

typedef void (*sighandler_t)(int);

函数的声明signal看起来像

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

对于函数 signal,您可以通过以下方式为其类型引入 typedef

typedef sighandler_t ( signal_t )( int, sighandler_t );

然后像

一样声明(但不定义)函数signal
signal_t signal;

这是一个演示程序,我希望它有助于理解 return 函数指针 or/and 具有函数指针类型参数的函数的函数声明。

#include <stdio.h>

void f( int x )
{
    printf( "%d ", x );
}

typedef void ( *FP )( int );

FP g( const int a[], size_t n, FP fp )
{
    for ( size_t i = 0; i < n; i++ )
    {
        fp( a[i] );
    }
    
    putchar( '\n' );
    
    return fp;
}

int main(void) 
{
    enum { N = 5 };
    
    int a[N] = { 1, 2, 3, 4, 5 };
    int b[N] = { 5, 4, 3, 2, 1 };
    
    FP fp = g( a, N, f );
    
    g( b, N, fp );
    
    return 0;
}

程序输出为

1 2 3 4 5 
5 4 3 2 1 

你必须考虑这一点并分阶段建立它。即使使用 typedef 也可能会造成混淆。 (如果没有 typedef,它甚至 更多 令人困惑!)

是的,信号处理程序是一个接受一个 int 并返回 void 的函数,就像这样:

void handler(int);

要创建一个指向这样的函数的指针,我们添加一个 *(表示一个指针)和一对括号以保持优先顺序:

void (*funcptr)(int);

要“命名”该类型——也就是说,将其简洁但抽象地描述为类型名称,但不提及标识符——我们实际上只是删除了标识符:

void (*)(int)

这是什么意思?好吧,如果我写 int 你知道我在谈论 C 的普通整数类型。如果我写 int * 你知道我在谈论一个指向 int 的指针。如果我写 void (*)(int) 你知道(一旦你理解了相当令人费解的命名法)我在谈论一个指向函数的指针,它接受 int 和 returns void.

因此,如果需要,我们可以从中创建一个 typedef:

typedef void (*sighandler_t)(int);

这里我在后面加了一个标识符(sighandler_t),在前面加了关键字typedeftypedef 的意思是 sighandler_t 不会像在常规变量声明中那样成为一个指向接受 int 并返回 void 的函数的指针——相反,它是一个aliassynonym 类型名称“指向采用 int 并返回 void 的函数的指针”。 (考虑 typedef 的一种方式是,它就像 #define,但在类固醇上。)

所以现在每当我们说 sighandler_t 时,就像说 void (*)(int) 或“指向函数的指针获取 int 并返回 void”。

现在,signal 是一个接受 (a) 信号编号和 (b) 指向该信号的新处理函数的指针的函数。所以是

signal(int sig, sighandler_t func)

也就是说,func 将成为指向信号处理函数的指针,该函数接受一个 int 并返回 void

但是 signalreturns 以前的信号处理程序,被传入的新 func 替换的那个。所以完整的是

sighandler_t signal(int sig, sighandler_t func)

希望这是有道理的。这是有道理的,因为 typedef 为我们执行了重要的符号简化。

如果没有 typedef,我们会有类似的东西

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

这几乎是完全不可读的。我不会试图想出一种从表面上解释这一点的方法。 (我也不打算描述我过去采用更简单、使用 typedef 的形式并在没有真正理解它的情况下机械地派生这个 jawbreaker 的容易出错的过程。)

在这种情况下,第二行将 signal 声明为一个函数,该函数接收指向类型为 sig_handler_t 的函数的指针作为其输入参数之一,并且 returns 是指向sig_handler_t 类型的函数。函数 signal 本身不是 sig_handler_t.

类型

在维基百科示例中,问题中的两行用于简化:

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

这里void (*func)(int)指定了一个参数func,它的类型等同于sig_handler_t。此外,用 void (* ... )(int) 包装声明将指定类型 sig_handler_t 的 return 值,尽管我从未见过有人在实践中这样做。