第二课问题之详解

    这里我们来看看第一个问题

   

问题:

这里我们可以得到 结束时状态值 status 256 ,这里为什么不是 exit()中传入的参数 呢?

如果我们修改子进程中exit 函数传入的值,我们可以发现得到的 status 传入值乘以 256.

这让我很费解,为什么不直接记录状态值而是要乘以256呢(表面上看来是这样的)?

 

我们同样可以查找函数源码来找到答案

 

通过查找 waitpid、_exit、以及WIFEXITED(status)和WEXITSTATUS(status)函数我们可以发现,在实际使用中,status 保存的

虽然是进程结束时的状态,但是,这个状态并不是就只有这一种情况下我们才会使用到。

观察 wait.h 文件

 

这里面包涵的宏就不止 WIFEXITED 这一个,还有WIFSIGNALED(status),WIFSTOPPED(status),WIFCONTINUED(status)

等,如果直接记录exit的传入参数值的话,就会有很大的局限性,并且很多时候我们不关心进程的退出状态,但是系统或者程序却要

关心,因此这样的做法应该是有它原来设计的时候的打算的。

 

    通过观察,我们可以看到,WIFEXITED 宏做的事情其实就是 把status 和 0x7f 位与然后判断结果是否等于0,这样除非我们传入的exit 的参数为0 否则它的执行结果一定不会是0。而我们需要知道非正常退出的时候只需要判断 WIFEXITED 返回值是否为0就可以了,如不是0 我们则可以 通过 WEXITSTATUS 宏来获取 退出时候的状态值。

    这个宏 我们看到这里执行的是 和 0xff00 位与然后向右移动8位,其实这里做的就是取s 的高八位值。原先我们看到的状态值被乘以256 的作用就能在这里体现出来了。因为乘以256其实就是想到与把s 的值 乘以2^8 就相当于向左移8位,这样我们就知道原来 status 的值并不是被乘以了256 而是被左移的8位。
   

    下面是一个测试程序 测试这WEXITSTATUS 宏的:

   

    我们同样可以把 WEXITSTATUS  改成 WIFEXITED 宏 这里我就不写了。

 

 

    关于问题二

    问题: 明明printf 函数在 fork函数之前 为什么 Test 打印了两次?

                 如果我们 fork 函数改成 vfork 是什么结果?

                 如果我们 在第一个printf函数里增加 ‘/n’ 又是什么结果?

 

    为什么Test 被打印了两次呢? 其实原因很简单,printf 是遇到/n 才输出并清空缓冲区的。

    观察测试程序执行过程:

    首先 父进程中的 Test 被放入缓冲区

    接着 生成子进程(注意,这里使用的fork 函数,因此父进程中的缓冲区也被复制到子进程,因此子进程缓冲区中也有 Test 字符),子进程执行printf 的时候遇到 '/n' 于是输出缓冲区的内容 

    所以输出的是 Test child exit 1.(注意这里有换行符)

       同时执行父进程的时候,原先缓冲区的Test并未被清空(因为子进程中缓冲区和父进程中的不是同一个),这样父进程执行prinft 函数的时候 遇到 '/n'也输出自己缓冲区的内容

       所以输出的是 Test father exit 1

       这样就解释了为什么 Test 被打印了两次。

       接着我们把fork 函数改成 vfork 函数结果是什么呢?

    还是执行过后我们看结果吧下面是我的执行结果:

     Testchild exit 1.
         father exit 1

        那为什么是这个结果呢?第二个输出为什么没有Test 呢? 原因在于,子进程使用的是vfork 生成的,并没有完全复制了父进程的数据段,而是采用了和父进程读写互斥的方法来使用数据段,因此在子进程执行了printf 之后缓冲区就被清空了,因此轮到父进程执行printf 的时候,缓冲区是没有Test 的。这是vfork和fork 的区别之一。

      

        在第一个printf函数里增加 ‘/n’ 又是什么结果?

     我想看到这里所有人都可以不用执行程序就能分析出结果,对了结果就是:

         Test

         child exit 1.
         father exit 1

        这个结果也是和我们预料到的结果是一样的。

   

    总结:

        对于很多程序,我们在写的时候往往都会忽略一些细节,这些细节往往就是我们程序产生莫名其妙的错误的原因。

    在读C缺陷和陷阱的时候,让我深刻体会到了这一点。在这里,我们通过一些我们常常困惑不解的例子来达到一样的效果。

    请记住 细节决定成败。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值