添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
c语言中的system函数可以说是程序执行时的一道重生之门,其重生妙效犹如我们之前《 透析硬链接和软链接的区别 》一文中的软链接文件。然而,system函数也带来了判断返回值的烦恼!本文分享我们对system函数的返回值的理解,希望对c语言学习者有所帮助(如有错误,还望指正,谢谢)。 先给出我们理解的 system函数执行原理 fork出子进程1,该子进程1通过execl来启动bash,bash会重新fork出一个子进程2去做实际的cmdstring命令,主进程会waitpid等待此子进程1的终结(潜在地,子进程1会等待子进程2)。 理解了这个执行过程,我们很容易完备枚举出system函数返回值的各个场景了。注意,我们在本文中会将此 返回值分为高8bit和低8bit两部分 (具体原因看完本文即可理解) 可见,在fork+execl+waitpid不能完美终结的情况下,也要 尽量靠近完美终结时的返回值方式 :高低8bit分别(独立)存储cmdstring和bash的返回值,并且倾向于将失败场景归入cmdstring的失败。这种倾向性,无可厚非,毕竟 求得cmdsting的返回值是system函数的核心业务。这样, cmdstring失败的错误码里预留了127给execl失败(或bash失败),也就是说cmdstring支持的返回值范围是[0..126]了,真是让人难以接受啊。。。 另外,我们看到,cmdstring的返回值是靠waitpid返回的,而此返回值经过了多道手:子进程2、子进程1、主进程,可谓繁琐至极(考虑换别的机制了?下次我们谈popen)。。。 综上, system函数的完美终结需要以下三个条件同时成立 :(status代表system函数的返回值)
1)status != -1 2)bash正常终结【即低8bit为0,或者说:WIFEXITED(status)为true】 3)cmdstring正常终结【即高8bit为0,或者说:WEXITSTATUS(status)==0】 上述引入的两个宏,具体含义如下: WIFEXITED(status) returns true if the child terminated normally, that is, by call‐ ing exit(3) or _exit(2), or by returning from main(). WEXITSTATUS(status) returns  the  exit  status  of  the child.  This consists of the least significant 8 bits of the status argument that  the  child specified  in  a  call to exit(3) or _exit(2) or as the argument for a return statement in main(). This  macro  should  only  be employed if WIFEXITED returned true . 可见, 一个聚焦于bash的终结,一个聚焦于cmdstring的终结,各有分工,互有所赖 :WEXITSTATUS(status)仅在WIFEXITED(status)为true时才能使用。 附上source code:(为方便理解,我们稍微做了修改) /* If WIFEXITED(STATUS), the low-order 8 bits of the status.  */ #define __WEXITSTATUS(status)   (((status) & 0xff00) >> 8) 另外,system函数里的waitpid函数还要和SIGCHLD信号的处理保持和谐共处:在主进程中需要mask SIGCHLD,waitpid之后再unmask SIGCHLD,这个mask/unmask处理是system函数内部完成的。否则, SIGCHLD的handler将完全可能破坏掉主进程的waitpid,从而无法保证system函数返回值的正确性了 (考虑这个场景:system函数的调用者的SIG CHLD的handler里也调用了waitpid,这样就架空了system函数里的waitpid)。。。 新浪微博( @NP等不等于P 计算机学习微信公众号(jsj_xx) 原创技术文章,感悟计算机,透彻理解计算机!