请教signal的问题

Posted xjbclz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请教signal的问题相关的知识,希望对你有一定的参考价值。

#include<stdio.h>
#include<signal.h>
#include<setjmp.h>
jmp_buf buf;
void handle(int s)

    if(i==SIGINT)printf("信号还没有到达\\n");
    longjmp(buf,2);

void main()

    signal(SIGINT,handle);
int i=setjmp(buf);


    if(i!=0)printf("the signal's return value:%d\\n",i);
    else printf("I will go handle\\n");
    
//在这里循环等待,直至输入Ctrl+c.
loop:
    goto loop;

请问为什么输入了ctrl+c后,结果是read错误呢?这个signal到底是怎么回事情呢?特别是第一个函数。什么时候该用什么呢?
signal(int, void (__cdecl *)(int))函数的原形是这个。signal(SIGINT,handle);书上这样写算怎么回事情呢?

 

lw8484654

应该是这样的,调试的时候忘记了改回来。请各位老大指教!
void handle(int s)

    if(s==SIGINT)printf("信号还没有到达\\n");
    longjmp(buf,2);

 

nuciewth

 

函数名: signal 
功  能: 设置某一信号的对应动作 
用  法: int signal(int sig, sigfun fname); 
程序例:


/* This example installs a signal handler routine for SIGFPE, 
   catches an integer overflow condition, makes an adjustment 
   to AX register, and returns. This example program MAY cause 
   your computer to crash, and will produce runtime errors 
   depending _disibledevent="sx">nuciewth

 

函数名: longjump 
功  能: 执行非局部转移 
用  法: void longjump(jmp_buf env, int val); 
程序例:


#include <stdio.h> 
#include <setjmp.h> 
#include <stdlib.h>


void subroutine(jmp_buf);


int main(void) 


   int value; 
   jmp_buf jumper;


   value = setjmp(jumper); 
   if (value != 0) 
    
      printf("Longjmp with value %d\\n", value); 
      exit(value); 
    
   printf("About to call subroutine ... \\n"); 
   subroutine(jumper);


   return 0; 


void subroutine(jmp_buf jumper) 
 
   longjmp(jumper,1); 


/*你的handle函数和这里的subroutine()应该差不多*/

 

lw8484654

你说的我都知道,我问的是,为什么运行会出现错误,大哥

nuciewth

loop:
     goto loop;

这里有什么意义??

其实我也不懂这个函数是怎样执行的,只想拿出来,大家瞧瞧,看别人怎么说.

论坛

先弄明白函数指针,signal的第2个参数是信号处理函数,当捕捉到指定信号时调用

king_2345484

#pragma inline
定义是什么意思啊 

 

king_2345484

jmp_buf buf;
是什么意思?

lw8484654

loop:
     goto loop;
要等信号,如果没有的话,程序就直接执行完了,signal的第一个参数是信号处理函数,第二个是函数.
在我的程序里运行的时候却是有错误,好象是返回不了.因为"信号还没有到达"这个可以打印出来!

lw8484654

有高手回答没.

soft_wind

signal函数的原型是void    (* _Cdecl signal(int sig, void (*func)(/* int */))) (int);
首先,signal函数接受两个参数:一个是整型的信号,一个是指向用户定义的信号处理函数的指针,
而它的返回值是一个指向调用前的用户定义信号处理函数的指针。
也许用下面这种写法会让您容易更明白些:
typedef void (*Fun)(int);
Fun signal(int,Fun);
至于jmp_buf buf;在"setjum.h"里有如下定义:
typedef struct
    unsigned    j_sp;
    unsigned    j_ss;
    unsigned    j_flag;
    unsigned    j_cs;
    unsigned    j_ip;
    unsigned    j_bp;
    unsigned    j_di;
    unsigned    j_es;
    unsigned    j_si;
    unsigned    j_ds;
   jmp_buf[1];
这个我没用过,也不清楚.

lw8484654

 

可能是操作系统的原因,因为我让朋友在LINUX的机子上试了,得到了我想要的答案.但是在WINDOWS上却得不到!!!

 

king_2345484

#pragma inline
定义是什么意思啊 

jmp_buf buf;
是什么意思?

lw8484654

非要是这么定义的,在头文件里.至于为什么jmp_buf buf;我也不是很清楚,头文件里是这样,所以我也要写成这样

ChenMo

 

信号处理

    UNIX(或其衍生系统)对信号的支持远比 DOS 要多,信号对之于DOS,可类比于中断(INT),
当某信号发生,转到信号处理函数执行,执行完毕后返回到转折点。

    定义某信号的处理函数可使用 signal,使用 raise 函数向当前程序(线程)产生一个信号。
    原型:
        void (*signal(int sig, void(*func)(int sig[, subcode] ))) (int);
        int raise(int signal);


    明显地,signal 是事前的一个预备(信号 sig 就像Windows的消息,func 所指的函数就像消息映射的处理函数),而 raise 函数导致信号发生。
    若 func 的值为SIG_DEF(常量指针),则执行系统默认的函数;若为 SIG_IGN 则忽略 sig 信号。

    以下信号是 UNIX 及 DOS 的通用信号(ANSI),若设置为执行默认操作的话,它们都会导致程序被中止:
    SIGABRT    异常中止时发生
    SIGPPE    算术运算出错时发生
    SIGILL    非法硬件指令
    SIGINT    中止程序(Ctrl+C,纯DOS)
    SIGSEGV    无效内存访问
    SIGTERM    中止信号

    以下是一个示例:

    #include "stdio.h"
    #include "conio.h"
    #include "signal.h"


    void PreExit(int);


    int main(void)
    
        puts("Press Ctrl+C Exit Program...");
        signal(SIGINT, PreExit);


        while('y' != getchar())
            ;


        puts("Exiting...");
        getch();


        return 0;
    


    void PreExit(int sig)
    
        puts("Do you want to exit this program?('y'es)");
    
 

 

lw8484654

 

在我的程序里,他是识别出了信号,但是却没有实行跳转,就是longjmp(),出现了“不知道的软件异常错误”.但是我在UNIX下却得以实现,是否操作系统不同导致的呢?

 

ChenMo

 

在循环内设置一个输入,才可以响应 Ctrl+C 中断,
信号处理函数执行完毕后,还需要为退出循环做好准备,
这是因为中断后转到信号处理,处理完毕后返回到转折点(循环内),
这将继续无限循环。


loop:
    if('y' == getchar())  /* 输入y结束程序 */
        exit(0);
    goto loop;

 

ChenMo

若需要关于异常处理的信息,可以联系本人。

lw8484654

老兄,你怎么联系呢?

lw8484654

老兄,我还希望在信号处理函数里面,通过longjmp(),跳转到setjmp啊,这一步是如何实现的呢?请指教!!!

ChenMo

 

只要经过 setjmp() 初始化,即可在任何时候调用 longjmp() 转跳到 setjmp() 函数位置,

setjmp() 与 longjmp()

原型:
    void _Cdecl longjmp(jmp_buf jmpb, int retval);
    int _Cdecl setjmp(jmp_buf jmpb);


    在使用 setjmp() 与 longjmp() 之前,需要弄懂一个数据结构 jmp_buf,
    此结构是 setjmp 接口(setjmp.h)的基本数据类型,jmp_buf 结构内容无须深入了解,
    只需要知道,jmp_buf 将记录某一时刻CPU寄存器的值即可,setjmp() 函数可以返回两次,
    第一次使用时作初始化一个 jmp_buf 的量(将当前CPU寄存器的值写入 jmpb 结构内),然后函数返回零;
    第二次是由异常抛出函数 longjmp() 引发,使 setjmp() 函数产生第二次返回,返回值为 retval。
    longjmp() 将 jmpb 内容恢复到寄存器内,执行位置将改变到 setjmp() 处,
    在调用后,longjmp() 后面的代码将毫无意义,并且越过前面所有的函数(将不会再经过 return 逐层返回),
    而是直接跳转到 setjmp() 位置。

    _Cdecl 声明函数的参数使用标准的进栈方式(由右向左)压栈。

异常处理
    goto 语句只可在函数内跳转,setjmp 与 longjmp 函数配合使用,
    可以实现在函数之间跳转(远程跳转),
    所以,C语言使用 setjmp() 及 longjmp() 实现异常处理机制。
    setjmp() 设置跳转位置,longjmp()实现转跳。

    在面向对象语言中由语言内部便提供了异常处理,如C++语言,
    使用 try 块包裹可能产生异常的代码(包括函数调用),
    catch 块用于编写异常处理代码;
    异常由手动的 throw 语句抛出。

    使用 C 简单地模拟 C++ 的异常处理语句是十分容易的,
    此前,值得说明一点的是:jmp_buf 声明的变量多数情况下需要被声明为全局的,
    这是因为 longjmp() 一般不在 try 块内部调用,try 块内一般会调用另外一些函数,
    而 longjmp() 经常在这些函数内抛出。

    jmp_buf Jump_Buffer;
    #define try if(!setjmp(Jump_Buffer))
    #define catch else
    #define throw longjmp(Jump_Buffer, 1)

下面的例程解释如何使用这些宏:
    
    /* 输入一个整型数,如果大于 100,则以异常抛出 */

    #include "stdio.h"
    #include "conio.h"
    #include "setjmp.h"

    jmp_buf Jump_Buffer;
    #define try    if(!setjmp(Jump_Buffer))
    #define catch  else
    #define throw  longjmp(Jump_Buffer, 1)

    int Test(int T);
    int Test_T(int T);

    int Test(int T)
    
        if(T > 100)    
            throw;
        else
            puts("OK.");

        return;
    
    int Test_T(int T)
    
        Test(T);
        return;
    

    int main(void)
    
        int T;

        try
        
            puts("Input a value:");
            scanf("%d", &T);
            T++;
            Test_T(T);
        
        catch
        
            puts("Input Error!");
        

        getch();
        return 0;
    

    当遇到 throw 抛出异常,立即转跳到 setjmp 处执行,
    屏弃了与之无相关的枝节(函数的返回及 throw 其后的代码)

    main [setjmp()] -> Test_T -> Test [throw]
           ↑                            ↓
           ┗━━━━━━━━━━━━━━┛

    当输入一个大于100的整数,throw 导致异常抛出,使用 1 返回到 setjmp() 函数处,
    宏 try 使 if(!setjmp(Jump_Buffer)) 不成立,执行 catch 块,
    catch 块是十分简单的 else 分支语句关键词的别称。

    这一组宏完成了对 setjmp() 及 longjmp() 两个函数的封装,使程序具备简单的异常处理功能。
    然而,遗憾的是这组宏不具备嵌套的能力,
    当这组宏应用到嵌套异常,只能响应最后一组异常宏,
    并且无法抛出异常类型,至少它连一个常量整型都无法抛出,
    这是因为 jmp_buf 全局只能存放一个 jmpb 结构。
    以下是对上面叙述的简单的图示:

    main()
    
        try
        
            Test_T();  ━━━┑
                            ┃
        catch                ┃
                            ┃
                            ┃
                            ┃
                             ┃
                             ┃
   Test_T() <━━━━━━━━┛
  
        try
        
            Test();  ━━━┑
                          ┃
        catch <━━━━━━┿━━━━━┑
                          ┃          ┃
                          ┃          ┃
                          ┃          ┃
                           ┃          ┃(只有最后一组宏可以响应异常)
                           ┃          ┃
    Test()<━━━━━━━━┛          ┃
                                      ┃
        if(True)                       ┃
            throw;   ━━━━━━━━━┛
    

    虽然这组宏无法嵌套使用,然而抛出一个常量整型是有可能的(甚至是一个结构struct),
    更改成如下一组宏,便可抛出一个常量整型,并且可以在 catch 处以 catch(Value)  的方式处理异常。

    jmp_buf Jump_Buffer;
    int     TValue;
    #define try         if( !( TValue = setjmp(Jump_Buffer) ) )
    #define catch(Val)  else if(TValue == Val)
    #define catch_all   else
    #define throw(Val)  longjmp(Jump_Buffer, Val)
    /* throw 抛出的值不应该等于0,因为这会导致无法执行try后面的catch块而继续执行形成了死循环*/

    下面的例程演示了这组宏:

    /* 输入一个整型数值,若大于 100 以异常抛出一个常量 20 
       否则以异常抛出一个常量 20 */

    #include "stdio.h"
    #include "conio.h"
    #include "setjmp.h"


    jmp_buf Jump_Buffer;
    int     TValue;
    #define try         if( !( TValue = setjmp(Jump_Buffer) ) )
    #define catch(Val)  else if(TValue == Val)
    #define catch_all   else
    #define throw(Val)  longjmp(Jump_Buffer, Val)


    int Test(int T);
    int Test_T(int T);


    int Test(int T)
    
        if(T > 100)
            throw(20);  /*只是演示,20这个常量值并无特别意义*/

        throw(10);      /* catch_all 块将处理这个异常*/
        return;
    


    int Test_T(int T)
    
        Test(T);
        return;
    


    int main(void)
    
        int T;


        try
        
            puts("Input a value:");
            scanf("%d", &T);
            T++;
            Test_T(T);
        
        catch(20)
        
            puts("Input Error!(Code: 20)");
        
        catch_all
        
            puts("Unknown error!");
        


        getch();
        return 0;
    

    正是因为 jmp_buf 全局只能存放一个 jmpb 结构,使得只有最后一组宏可以响应异常;
    这是无法嵌套异常的原因,
    要实现多重嵌套可以建立一个全局堆栈来维护一组 jmpb 结构,
    此处不给出实现,若感兴趣请自行实现,文中若有错误,欢迎指正。
    这里给出的只是C异常处理的简单实现,若要完善的异常处理,这需要更多的手段。


[align=right][color=#000066][此贴子已经被作者于2006-9-6 16:36:35编辑过][/color][/align]

 

lw8484654

对的,老兄,那么关于signal()这个函数之所以会出现运行错误好象没有解释啊!!!

ChenMo

 

我无法确定你是否是因为系统差异的问题,
我对异常处理(setjmp)还算熟悉,
而 signal及 raise 我使用得甚少(事实上我用C那么久我只用了三次,在为你调试程序时的那次也算)。

我的建议是:

在下面程序中插入一个 getchar()
loop:
    getchar();
    goto loop;

这是因为,若不设置 getchar() 输入可能会导致连 Ctrl+Break 中断信号都无法识别,
至于为什么,我只能说对不起——以我目前的能力无法向您解释,惭愧,
我研究了一晚上查了几本大全都无法找到答案,抱歉。

我只确定若使用 raise 函数向当前程序发送 SIGINT 信号必然可以使 Ctrl+Break 处理函数 handle 响应。

关于跳转:
    我此处可以跳转,您的程序至少应该将 int i 定义在 signal 函数前面,因为 signal() 是执行语句,
    int i=setjmp(buf); 此句中包含声明 i 变量,应该在当前复合语句中执行语句的前面。

    如这样写:
        int i;
        i = setjmp(buf); 
        signal(SIGINT, handle);

无法给你满意的答案,我向你道歉。

 

阅读全文:http://bbs.bc-cn.net/dispbbs.asp?boardID=5&ID=87994

以上是关于请教signal的问题的主要内容,如果未能解决你的问题,请参考以下文章

请教一个VHDL的问题

请教matlab程序错误

Python和Signal

c的signal函数

signal信号

Flask 信号机制 (signals)