原文链接
有如下代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int glob = 10;
int main(void) 
{
    int var;
    var = 88;
    pid_t pid;
    if ((pid = vfork()) < 0) 
    {
        printf("vfork error");
        exit(-1);
    }else if (pid == 0) 
    { /* 子进程 */
        var++;
        return 0;
    }
    printf("pid=%d, glob=%d, var=%d\n", getpid(), glob, var);
    return 0;
}

编译运行后提示段错误.原文中讲了主要原因:
vfork确保子进程先运行,并且与父进程共享内存,因此在子进程中不能使用return返回,如果使用return返回会破坏父进程的栈。
我们可以看到man手册中的解释:

vfork() differs from fork(2) in that the calling thread is suspended until the child terminates (either normally, by calling  _exit(2),  or  abnor‐mally,  after delivery of a fatal signal), or it makes a call to execve(2).  Until that point, the child shares all memory with its parent, includ‐ing the stack.  The child must not return from the current function or call exit(3), but may call _exit(2).

exit与系统调用_exit()的区别是:
exit(status)会执行如下动作
1.调用退出处理程序,通过atexit()和onexit()注册的函数, 执行顺序与注册顺序相反
2.刷新stdio缓冲区
3.使用由status提供的执行_exit()系统调用
为了验证我们上面所说的第二点我们可以编写如下代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int pid = 0;
    printf("Hello world\n");
    write(STDOUT_FILENO, "Ciao\n", 5);
    if ((pid = fork()) < 0)
        exit(EXIT_FAILURE);
    else if(pid == 0)
        exit(EXIT_SUCCESS);
    else
        exit(EXIT_SUCCESS);
}

使用gcc 编译后假设可执行文件为hello,如果执行./hello >out,那么会输出两遍Hello world,如果将上述程序修改成下面,则out中只有一遍Hello,world.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int pid = 0;
    printf("Hello world\n");
    write(STDOUT_FILENO, "Ciao\n", 5);
    if ((pid = fork()) < 0)
        exit(EXIT_FAILURE);
    else if(pid == 0)
        _exit(EXIT_SUCCESS);
    else
        exit(EXIT_SUCCESS);
}

原因是子进程可以调用_exit()不再刷新stdio缓冲区。因此只输出一遍Hello world。
下面解释另一个问题:
当重定向时为什么输出了两遍Hello,world呢?
在进程的用户空间内存中维护stdio缓冲区,因此通过fork创建子进程时会复制这些缓冲区。当标准输出重定向到终端时因为缺省为行缓冲,所以printf输出包含换行符的字符串。当标准输出重定向到文件时,由于缺省为块缓冲所以,调用fork时printf输出的字符串仍在父进程用户控件stdio的缓冲区中,子进程复制了一份。父子进程调用exit刷新各自的缓冲区,从而导致重复的输出结果。正如同我们上面的试验一样,假如子进程退出时使用_exit那么不会刷新缓冲区,因此只打印了一次Hello world.