关于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"); } }
原代码的工作流程
- 进入
tfgets函数,第一次调用setjmp(buff)会保存当前执行上下文到buff,返回0,因此进入if分支。 - 设置SIGALRM信号的处理函数为
handler,随后调用alarm(5)启动一个5秒的定时器:- 如果5秒内用户通过stdin输入内容,
fgets会成功读取并返回,函数正常返回输入缓冲区指针,同时未触发的定时器会被自动清除。 - 如果5秒内无输入,SIGALRM信号触发,
handler调用longjmp(buff,1),此时会跳回之前setjmp保存的上下文,setjmp会返回1,进入else分支,函数返回NULL。
- 如果5秒内用户通过stdin输入内容,
交换两行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 } }
- 第一次调用
setjmp(buff)返回0,进入if分支,此时直接执行return NULL,函数立即结束并返回NULL,根本没有机会调用fgets进入阻塞等待状态。 - 虽然
alarm(5)被调用启动了定时器,但函数已经提前返回,定时器还没到触发时间就随着函数执行结束失去意义,自然不会有后续的信号触发和跳转逻辑。
简单说,交换return位置后,代码跳过了阻塞等待的fgets,直接在初始化跳转点的分支里返回了NULL,所以函数会立即返回。
内容的提问来源于stack exchange,提问作者0xhello
相关产品推荐
相关产品推荐

