OSX"非法指令4"具有嵌套功能

con*_*com 0 c macos gcc

这里的目标是捕获SIGINT以关闭小型套接字服务器上的服务器套接字.我试图使用嵌套函数来保持代码清洁.但...

当我做Ctrl-C(SIGINT,对吗?)时,我明白了Illegal instruction: 4.阅读这篇文章后,我已经尝试添加-mmacosx-version-min=10.8到编译标志,因为我在10.8.执行Ctrl-C时出现相同的错误.

这里有两个问题:为什么我会得到"非法指令4"?如何在不使用全局变量的情况下关闭服务器套接字?

我的软件:

Mac OSX 10.8.4
GCC 4.2.1
Run Code Online (Sandbox Code Playgroud)

这是我正在编译的方式:

gcc -fnested-functions main.c
Run Code Online (Sandbox Code Playgroud)

这是代码:

#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

void register_sigint_handler(int *serverSocket)
{
    void sigint_handler(int signal) {
        printf("Shutting down...\n");
        printf("Server socket was %d\n", *serverSocket);
        close(*serverSocket);
        exit(0);
    }
    signal(SIGINT, &sigint_handler);
}

int main(void) {
    int serverSocket = 0, guestSocket = 0;

    register_sigint_handler(&serverSocket);

    serverSocket = socket(PF_INET, SOCK_STREAM, 0);

    while (1) {}

    close(serverSocket);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

nos*_*nos 6

虽然我不能具体告诉你发生了什么,但gcc文档有一个概括:

如果你尝试在包含函数退出后通过其地址调用嵌套函数,那么所有的地狱都会破裂.

将函数指针传递给signal()将完全相同,在包含函数退出后调用本地函数.所以你不应该将嵌套函数指针传递给signal()

您应该只为处理程序使用普通函数,它设置一个标志.

static volatile int do_exit;
void sigint_handler(int sig)
{
   do_exit = 1;
}
Run Code Online (Sandbox Code Playgroud)

在服务器中,通常有一些主循环,例如select或poll,你的主循环,空循环现在可以成为

while (!do_exit) { 
  pause(); 
}
Run Code Online (Sandbox Code Playgroud)

(请注意,当进程退出时,操作系统会自动关闭套接字;)


zwo*_*wol 5

" 那么,不要这样做. "

GCC的嵌套函数在C扩展中提供真正的闭包.当你取地址时sigint_handler,一个"蹦床"(一小段自修改代码)写入堆栈; 一旦register_sigint_handler退出,蹦床就会被摧毁; 随后尝试调用蹦床(由内核,以便调度信号)导致未定义的行为.

根据定义,信号处理程序是进程全局的.因此,原则上试图避免在信号处理程序中使用全局变量是 不正确的.想象一下你要做什么来使这个代码处理两个服务器套接字:你只能SIGINT注册一个处理程序,所以不知何故它必须关闭两个套接字.

当您的流程终止时,所有打开的文件描述符都会自动关闭. 因此,没有必要先用手关闭它们.此外,成功退出是违反惯例的^C. 如果这个程序是由监督程序驱动的,那么该程序就会想知道(通过waitpid状态代码)它是否因为a而退出SIGINT.把这两件事放在一起,你根本就不应该有这个信号处理程序.

(这将停止,如果你需要为真的东西退出你的主动套接字.举例来说,如果你想写的东西退出每个活动的客户端连接,你会希望有一个信号处理程序.但在这一点上要让信号处理程序警告主事件循环,然后在那里工作.)

(考虑使用libevent这种事情,而不是自己做所有低级别的goo.)