You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于alarm()函数工作机制的疑问:交换代码行后函数立即返回的困惑

关于alarm()函数与setjmp/longjmp的行为分析

先看你提供的原代码逻辑:

jmp_buf buff; 

void handler(){ 
   longjmp(buff,1);
}

char* tfgets(char * str, int n ,FILE * stream){ 
  if   (!(setjmp(buff))){ 
    if(signal(SIGALRM, handler) == SIG_ERR){ 
      char * err_str= "Signal cant be added";
      write(STDOUT_FILENO, err_str, strlen(err_str));
    }
    alarm(5);
    return fgets(str,n,stream); // 原位置的返回语句
  }else{
    return NULL;                // 原else分支的返回语句
  }
}

int main(int argc, char** argv, char**envp){ 
    char buf[100];
    char* input = tfgets(buf, 100, stdin);
    if (input == NULL) { 
        printf("not typed");
    }else { 
        printf("typed");
    }
}

原代码的工作流程

  1. 进入tfgets函数,第一次调用setjmp(buff)会保存当前执行上下文到buff,返回0,因此进入if分支。
  2. 设置SIGALRM信号的处理函数为handler,随后调用alarm(5)启动一个5秒的定时器:
    • 如果5秒内用户通过stdin输入内容,fgets会成功读取并返回,函数正常返回输入缓冲区指针,同时未触发的定时器会被自动清除。
    • 如果5秒内无输入,SIGALRM信号触发,handler调用longjmp(buff,1),此时会跳回之前setjmp保存的上下文,setjmp会返回1,进入else分支,函数返回NULL。

交换两行return后的问题原因

当你把return fgets(...)和return NULL交换位置后,代码的执行路径完全改变:

char* tfgets(char * str, int n ,FILE * stream){ 
  if   (!(setjmp(buff))){ 
    // ... 信号设置和alarm(5)
    return NULL;                // 现在直接在这里返回
  }else{
    return fgets(str,n,stream); // else分支才调用fgets
  }
}
  1. 第一次调用setjmp(buff)返回0,进入if分支,此时直接执行return NULL,函数立即结束并返回NULL,根本没有机会调用fgets进入阻塞等待状态。
  2. 虽然alarm(5)被调用启动了定时器,但函数已经提前返回,定时器还没到触发时间就随着函数执行结束失去意义,自然不会有后续的信号触发和跳转逻辑。

简单说,交换return位置后,代码跳过了阻塞等待的fgets,直接在初始化跳转点的分支里返回了NULL,所以函数会立即返回。

内容的提问来源于stack exchange,提问作者0xhello

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 18:35:23