返回类型为void的原因(* signal(int signo,void *(func)(int)))(int)

时间:2018-03-26 11:28:25

标签: c linux function signals function-pointers

typedef void (*sighandler_t)(int);
extern sighandler_t signal(int signum, sighandler_t handler); // 1
extern void (*signal(int sig, void (*func) (int)))(int);      // 2

1 2 是彼此的等价物。这个问题并不是从 如何开始的。我从以下描述中很好地理解了它的声明及其作用。

  

一个带int的函数和一个指向函数的指针(int   返回void)并返回指向函数的指针(取int   并返回虚空)。

  

sighandler_t是一个指向int的函数的指针   参数并且什么都不返回signal函数需要这样的   函数指针作为其第二个参数。它还返回一个函数   那种类型的指针。

为什么选择intvoidsomething else的返回类型代替指向函数的指针(取int并返回void与第二个参数相同?也就是说,我想知道是否有任何理由选择返回类型。

2 个答案:

答案 0 :(得分:4)

  

为什么它的返回类型没有选择int或void或其他代替指向函数的指针(取int并返回void)与第二个参数相同?

signal()返回该信号的上一个处理程序。因此,如果要在设置不同的处理程序后恢复信号的旧行为,这将非常有用。

对于sigaction(),旧处理程序通过其第三个参数返回;因此它返回int

答案 1 :(得分:1)

来自the POSIX signal() documentation

  

返回值

     

如果请求得到遵守,signal()将返回值   func用于指定信号的signal()最近一次调用   sig。否则,将返回SIG_ERR并返回正值   应存储在errno

如@ P.P。的回答所述,这是该信号的先前信号处理程序,允许恢复旧处理程序以及链接信号处理程序调用的能力。

链接信号处理程序示例:

typedef void ( *sighandler_t )( int );

sighandler_t old_handler = NULL;

void new_handler( int sig )
{
    switch ( sig )
    {
    case SIGTERM:
        // do your own handling
           .
           .
           .

        // now call the old handler
        if ( old_handler )
        {
            old_handler( sig );
        }
        break;
    default:
        break;
    }

    return;
}

int main( int argc, char **argv )
{
        .
        .
        .

    // save the old handler so it can also be called
    old_handler = signal( SIGTERM, new_handler );

    // make sure old_handler isn't a non-function
    // (these can be extremely platform-specific)
    if ( old_handler == SIG_ERR ||
         old_handler == SIG_DFL ||
         old_handler == SIG_IGN )
    {
        old_handler = NULL;
    }
}

你必须要小心,不要把某些不能被召唤的东西联系起来。对于上面的示例,代码检查以确保signal()的返回值不是信号处理程序的已知非可调用值之一。

链接还有其他问题。例如,如果您安装自己的SIGSEGV处理程序并使用上面的代码,那么如果您的signal()调用安装了一个持久性处理程序(一个不需要signal()调用的实现重新安装自己的处理程序)或者如果您使用sigaction(),并且原始SIGSEGV处理程序是SIG_DFL,则不会调用默认处理程序。如果取消引用SIGSEGV指针,这将导致进程进入无限NULL循环,因为在处理程序返回后将再次运行无效指令。