每日一题(十三)

10.26 数据缓冲区造成的错误

有时候,写类似如下的代码:
在这里插入图片描述

会一直输出,我们的本意是一次输入完成,再进行一次输入。

原因是scanf是从缓冲区读取输入进行赋值的,上次的输入数据还在缓冲区,就导致程序一直在判断上次的缓存数据。

处理方法就是在scanf读取缓冲区的数据之后,利用getchar函数把缓冲区的数据取出来。

10.27 整数溢出

C语言中有两种整数运算:

  • 无符号运算
  • 有符号运算

其中无符号运算不存在“溢出问题”,因为无符号运算是以2地n次方为模;

如果算术运算符地一个操作数是有符号整数,另一个是无符号整数,有符号会自动转换成无符号整数来进行运算,所以也保存在“溢出问题”;

但是两个有符号操作数进行运算的时候就可能溢出,而且溢出地结果是未定义的,解决方法就是将有符号数强制转换为无符号数,或者声明为long来保证数据的范围;

10.28 运算符的求值顺序

C语言中有四个运算符存在求值顺序,分别是:

  • && 与运算
  • || 或运算
  • ?:三目运算
  • , 逗号运算

其中&&||都是先对左侧的操作数求值,在有需要的时候才对右侧的操作数求值

a?b:c是先求a的值,根据结果来去选择b或者是c

,逗号运算符是先对左侧的操作数求值,返回的是最右侧的操作数求值结果

10.29 包裹函数

包裹函数就是用户自己实现的函数,函数中包裹了原函数的操作以及对原函数出错的处理,相当于在原函数之上的又一层封装。

在这里插入图片描述

看起来包裹函数就是对调用底层函数出错的处理,测试原函数返回值,但实际上这种看似多余的操作在多线程的时候会节省保存出错标志的变量。因为包裹函数调用完毕之后会销毁内存空间。

10.30 父进程调用wait()函数

调用了 wait() 函数的父进程会马上阻塞自己, 由 wait()函数自动分析是否当前进程的某一个子进程已经退出, 如果找到了这样一个已经变成了僵进程的子进程, wait()函数就会收集这个子进程的信息, 将他彻底终止并返回子进程结束状态值, 如果没有找到这样的一个子进程, wait()函数就会一直阻塞在这里, 直到出现一个变成僵进程的子进程出现为止, 但如果父进程还未调用 wait()函数就终止了, 此时子进程就将被 init 进程收管, 他将控制子进程退出后必须的清除工作。

10.31 fork与vfork区别

fork创建的子进程只是与父进程共用代码段,自己会开辟新的数据段。

父进程fork创建子进程之后,子进程相当于复制了父进程的所有代码,但是子进程会从fork开始执行。因为进程是程序的动态执行,当父进程执行到fork的时候,前面的已经执行完毕,所以能够复制过去的只有代码(静态?)和父进程当前的执行状态了,子进程创建之后会以父进程的状态进行执行。

fork之后,子进程是复制父进程的内存大小、命名空间、框架,而不是同一个空间,所以里面的数据可能是不一样的。

子进程和父进程的运行状况与CPU的运行状态以及进程的调度方式有关,所以父子进程的先后运行顺序不一定(平等竞争)。

父进程创建子进程之后,子进程就是一个单独的进程了,和父进程一同竞争CPU的使用资源。

另外对于gdb中涉及到子进程的创建,可以设置gdb追踪模式来专门追踪子进程,也可以是gdb继续调试当前进程。

默认是继续执行子进程的,但是当在gdb中持续调试的时候,遇到fork之后可能出现子进程运行的现象,这是因为父进程还在调试中,子进程不受gdb的影响,先执行完毕了。同理,设置只追踪子进程的时候,父进程一般会在子进程还在gdb的时候就执行完毕。

vfork创建的子进程是与父进程共享数据的,子进程上的内存空间和父进程共用,这样带来的影响就是,当变量在子进程中改变是,变量在父进程中的值也会随之改变!

posted @ 2020-11-12 07:53  Aspirant-GQ  阅读(35)  评论(0编辑  收藏  举报