Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C-高阶函数_C - Fatal编程技术网

C-高阶函数

C-高阶函数,c,C,信号将回调函数作为其参数之一。为了具有可变行为,我想在函数中创建一个函数。这是我迄今为止的尝试: typedef void (*sighandler_t)(int); sighandler_t f(int pid) { void sigintHandler(int sig) { printf("Process %d", pid); } return sigintHandler } int main(void) { ... if (sign

信号将回调函数作为其参数之一。为了具有可变行为,我想在函数中创建一个函数。这是我迄今为止的尝试:

typedef void (*sighandler_t)(int);
sighandler_t f(int pid) {
    void sigintHandler(int sig) {
        printf("Process %d", pid);
    }
    return sigintHandler
}

int main(void) {
    ...
    if (signal(SIGTSTP, *f(1)) == SIG_ERR) {
        ...
    }
    ...
}
但是,每次我发送一个SIGTSTP(Ctrl-z),我都会得到一个seg错误



作为旁注:任何关于如何调试seg故障的提示都非常感谢

我不确定你在问什么,但我可以帮助你理解你的错误

当你调用一个函数时,有几件事要做

  • 将函数参数推送到堆栈
  • 将返回地址推送到堆栈
  • 跳转到函数地址
  • 功能体
  • 从堆栈中弹出返回地址
  • 从堆栈中弹出函数参数
  • 当调用作用域完成1、2、6时

    如您所知,信号是一个
    无效参数
    ,因此调用(1)将
    0
    参数推送到堆栈中

    而返回(6)将从堆栈中弹出“unexistant”
    int
    ,并损坏它

    解决方案

    您不能有带参数的信号函数,
    你能做的是:

  • 您可以在信号函数中读取全局变量。并因此读取程序的当前状态

  • 您可以通过sys\u调用来获取进程id、线程id

  • 我不建议您这样做,但您可以将堆栈进一步读取到前面的范围,并获取其局部变量。值得注意的是,这将不是你设置信号的功能。。。但是在发出信号时正在运行的功能


  • 您的代码可以编译,因为它在语法上是正确的,并且您正在使用编译器扩展;但是,代码中存在一些基本问题,可能会导致出现
    segfault

    首先,您的信号处理程序代码:

    typedef void (*sighandler_t)(int);
    sighandler_t f(int pid) {
        void sigintHandler(int sig) {
            printf("Process %d", pid);
        }
        return sigintHandler;
    }
    
    这是,甚至需要在某些版本的
    gcc
    上指定标志才能实际编译

    您的信号处理函数本身有一些问题需要解决:

    sigintdhandler
    是a,因此当信号处理函数
    f
    通过
    返回sigintdhandler,您将返回一个函数指针

    在您的代码中,这可以正确编译,因为您有
    typedef void(*sighandler_t)(int)
    ,它定义了一种函数指针类型,该类型可以指向具有
    void
    返回类型的函数,并将
    int
    作为参数,而
    sigintHandler
    定义为该参数

    相反,您的信号处理函数可以简单地写为:

    void sigintHandler(int sig) {
        printf("Signal %d\n", sig);
    }
    
    在主要功能中,您具有以下功能:

    if (signal(SIGTSTP, *f(1)) == SIG_ERR) {
        // ....    
    }
    
    if (signal(SIGTSTP, f) == SIG_ERR) {
        // ....    
    }
    
    #include <stdio.h>
    #include <signal.h>
    
    void sigintHandler(int sig) {
        printf("Signal %d", sig);
    }
    
    int main(void) {
        // ...
        if (signal(SIGTSTP, sigintHandler) == SIG_ERR) {
            // ...
        }
        // ...
        return 0;
    }
    
    #include <stdio.h>
    #include <signal.h>
    #include <unistd.h>
    
    void sig_stop(int sig) {
        printf("Process %d stop\n", getpid());
    }
    
    void sig_int(int sig) {
        printf("Process %d interrupt\n", getpid());
    }
    
    int main(void) {
        // ...
        if (signal(SIGTSTP, sig_stop) == SIG_ERR) {
            // ...
        }
        if (signal(SIGINT, sig_int) == SIG_ERR) {
            // ...
        }
        // ...
        return 0;
    }
    
    这里应该指出,这也有一些问题。首先,函数的第一个参数是信号号(通常是标头中定义的宏),第二个参数是指向定义为
    void func_name(int sig)
    的函数的指针

    为此,您正在调用函数,而不是将其作为指针传递

    *f(1)
    实际调用
    f
    传递
    1
    作为其参数;相反,您可以将其更改为以下内容:

    if (signal(SIGTSTP, *f(1)) == SIG_ERR) {
        // ....    
    }
    
    if (signal(SIGTSTP, f) == SIG_ERR) {
        // ....    
    }
    
    #include <stdio.h>
    #include <signal.h>
    
    void sigintHandler(int sig) {
        printf("Signal %d", sig);
    }
    
    int main(void) {
        // ...
        if (signal(SIGTSTP, sigintHandler) == SIG_ERR) {
            // ...
        }
        // ...
        return 0;
    }
    
    #include <stdio.h>
    #include <signal.h>
    #include <unistd.h>
    
    void sig_stop(int sig) {
        printf("Process %d stop\n", getpid());
    }
    
    void sig_int(int sig) {
        printf("Process %d interrupt\n", getpid());
    }
    
    int main(void) {
        // ...
        if (signal(SIGTSTP, sig_stop) == SIG_ERR) {
            // ...
        }
        if (signal(SIGINT, sig_int) == SIG_ERR) {
            // ...
        }
        // ...
        return 0;
    }
    
    但这会发出警告/错误,因为
    f
    被定义为返回函数指针,而不是
    void

    因此,要将代码更改为兼容,您只需执行以下操作:

    if (signal(SIGTSTP, *f(1)) == SIG_ERR) {
        // ....    
    }
    
    if (signal(SIGTSTP, f) == SIG_ERR) {
        // ....    
    }
    
    #include <stdio.h>
    #include <signal.h>
    
    void sigintHandler(int sig) {
        printf("Signal %d", sig);
    }
    
    int main(void) {
        // ...
        if (signal(SIGTSTP, sigintHandler) == SIG_ERR) {
            // ...
        }
        // ...
        return 0;
    }
    
    #include <stdio.h>
    #include <signal.h>
    #include <unistd.h>
    
    void sig_stop(int sig) {
        printf("Process %d stop\n", getpid());
    }
    
    void sig_int(int sig) {
        printf("Process %d interrupt\n", getpid());
    }
    
    int main(void) {
        // ...
        if (signal(SIGTSTP, sig_stop) == SIG_ERR) {
            // ...
        }
        if (signal(SIGINT, sig_int) == SIG_ERR) {
            // ...
        }
        // ...
        return 0;
    }
    
    任何关于如何调试seg故障的提示都将不胜感激

    首先,了解a是什么;然后,您可以使用调试器,如单步执行代码或检查崩溃转储,以查看发生故障的具体位置


    希望能有所帮助。

    标准C不支持在其他函数中定义函数,因此这完全依赖于编译器。为什么需要在另一个函数中定义函数?此外,根据“如果你试图在包含函数退出后通过其地址调用嵌套函数,那么所有的麻烦都会发生。”你不能将
    pid
    放入一个全局变量中(它应该是
    volatile sig\u atomic\u t
    )。是的,我想我可以使用一个全局变量。我是一个相当新手的C程序员,在其他地方,我通常被教导调试任何东西(包括seg故障),使用
    -g
    选项编译程序(假设您使用
    gcc
    ),并在调试器下运行。好吧,这不可能工作
    pid
    仅在
    f()的生存期内存在。在
    main()
    中,您正在将
    sigintHandler
    传递给
    signal()
    。当调用
    sigintHandler()
    时,
    f()
    就再也找不到了,而且
    pid
    的生命周期也结束了。