首页 > C语言高手帮忙分析一下复杂的函数声明

C语言高手帮忙分析一下复杂的函数声明

C语言高手帮忙分析一下下面这个复杂的声明,最好有详细步骤:

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

该函数原型来自C语言标准库 signal.h.


cvoid (*signal(int sig, void (*handler)(int)))(int);
                       ^^^^^^^^^^^^^^^^^^^^^
                       // 是函数指针,设为 Func1
void (*signal(int sig, Func1))(int)
       ^^^^^^^^^^^^^^^^^^^^^^
       // 是普通函数,设为 Func2
void (*Func2)(int)
^^^^^^^^^^^^^^^^^^
// 是函数指针,设为 Func3

于是该函数声明可简化为:

cFunc1 signal(int, Func1);

还觉得难吗?


再补充上用法吧,可能更加清楚:

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

void (*prev_handler)(int); // 声明一个函数指针
prev_handler = signal (SIGINT, my_handler); 

应该很清楚了,该函数声明中,主体是 Func2, 返回值与参数 2 的类型都是 Func1.


c变量的声明有两部分组成:类型和声明符,对声明符求值得到结果类型为给定的类型。

举个最简单的例子

int a;

a的类型就是上述声明中指定的类型,即int型。

同样,在来看指针和函数的声明,这里不考虑指针的初始化问题。

int * p;
int foo1(void);
int *foo2(void);
int (*foo3)(void);

*p求值结果的类型为int型,因此p的类型就是指向int型变量的指针。
foo1(void)求值结果为一个int型数,那么foo1就是返回值为int型数的函数,无参数。

注意第三个声明,()的优先级高于*,因此*foo2(void)可以看作*(foo2(void)),对其求值结果为一个int型数,那么foo2(void)结果就是指向int型数的指针,因此foo2是返回值为指向int型数指针的函数。
第四个声明中,(*foo3)(void)求值结果是int数,因此(*foo3)为返回值为int数的函数,最终得出foo3是指向这个函数的指针,即foo3指向返回值为int型数的函数。

上面就是基本的类型声明,不论多复杂的函数声明都是用上述的声明方式组合而来的。在分析题中的函数声明之前,再说明一下类型转换符,c中需要强制转化一个数据类型时,在数据前加上(类型关键字),比如

int a;
a = (int)(1.0);

简单类型可以这样,那么复杂类型怎么做强制转化呢?其实很简单,将之前定义类型声明语句的变量名和;去掉,再将剩余的部分还是放在一个括号中就可以了,其实也适用于简单类型。

int (*foo4)(void);

上面的声明定义了指向返回值为int型数的函数的指针,那么该类型的类型转换符为(int (*)(void))

最后回到题中的函数声明。

先来分析signal函数的参数,一个为代表信号的int型数,一个指向信号处理函数的指针,那返回值呢?返回值就是指向信号处理函数的指针。

再来看看信号处理函数定义,参数为代表信号的int型数,无返回值。

void sigfunc(int n)
{
    /*
    信号处理代码
    */
}

那么现在可以得到这个自定义的信号处理函数声明

void sigfunc(int);

怎么得到一个指向自定义的信号处理函数的指针呢?很简单,假设该指针名为pfunc,则*pfunc就代表了sigfunc函数,因此指向自定义信号处理函数的指针声明为

void (*pfunc)(int);

signal函数的返回值类型与pfunc类型相同,即pfunc可由signal(arg1,arg2)代替,其中arg1arg2分别为代表信号的的int型数和指向自定义信号处理函数的指针。

void (*signal(int n,void (*pfunc)(int)))(int)

将其中的变量名省略就是signal函数的声明

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

以上都是我自己参考<C陷阱与缺陷>中第2章而写,之前自己看过一边,在这个问题上一直没有较深理解,这次回答也相当于自己再思考一遍这个问题,希望大家指点。


signal 返回值是 void(*)(int) 类型的函数指针

void (signal(int sig, void (handler)(int)))(int);
这样声明,考虑过可读性了么,考虑过维护性了么


这已经算简单的了

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

下面来改写

typedef void (*Handler)(int);
typedef void (*Result)(int);
typedef Result (*Signal)(int sig, Handler handler);

已经快一年没用过C了,不知道有没有语法错误。


signal() 函数,有两个参数:int sigvoid (*handler)(int)
返回值是 void(*)(int) 类型的函数指针


这个函数:

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

在UNIX网络编程 volume 1(3th edition)P105页上看到过。
我的理解。
首先你得区分函数指针和指针函数,不然你看相关解释可能会晕。简单地说,函数指针指向的是一个函数;函数指针说的是这个函数的返回类型是一个指针。

 void ( *func )( int ) 

就是一个函数指针,指向的目标函数的参数是int型,即指向的目标函数是这样的类型:void func(int)。意思就说指向要处理信号的函数。
void ( *signal())( int )表明signal函数是一个指针函数,即就是返回的是一个指针。该指针指向函数,而指向的函数的类型是void func(int).
书上接着定义了typedef void Sigfunc( int )
那么整个函数就可以简写为:Sigfunc *signal( int signo, Sigfunc *func );
-------------------额外的---------------------
信号处理分有两种方法:
1)POSIX方法是调用sigaction函数。2)ANSI C提供的方法是signal.h中的signal()函数。
两种方法有一定得差异吧,于是就定义了自己的信号处理函数。达到的效果就是使用了POSIX函数但是却定义了简单地接口(要知道sigaction函数要三个参数还要自己分配填写结构)
希望对你有帮助 :D

【热门文章】
【热门文章】