write()输出缺失

时间:2016-06-30 23:30:54

标签: c terminal output

main(int argc, char *argv[]) {

  //variables
  int status, fout, waitcall;
  pid_t pid, ppid, cpid;

  pid = getpid();

  //write to terminal
  write(fout, "Hello World - I am parent:  ",29);
  write(1, (void*)&pid, sizeof(pid));
  write(1, "  !!\n\n", 7);

  int returnchild = fork();

  // fork failed; exit
  if ( returnchild < 0 ) {
    //fail code
  }

  // child (new process)
  else if ( returnchild == 0 ) {
    //getpid(), waitpid() then write;

    if ( waitcall == -1 ) {
        perror("waitpid\n\n");
        exit( EXIT_FAILURE );
    } // end if
}

// parent goes down this path
else {
   //some code here    
}
return 0;
} // end main
  

我想要输出到终端,这样我就能理解程序的位置。不输出到终端?正在使用printf但想使用系统调用。

1 个答案:

答案 0 :(得分:1)

代码存在多个问题,包括您提供的内容并非真正的MCVE(Minimal, Complete and Verifiable Example)。

这是修改后的代码,紧密基于您的代码,代码中的一些缺陷仍然存在,但其他修复。添加了一些额外的仪器。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(void)
{
    int status, waitcall;
    pid_t pid = getpid();

    // write to terminal
    write(STDOUT_FILENO, "Hello World - I am parent:  ", 29);
    write(STDOUT_FILENO, (void *) & pid, sizeof(pid));
    write(STDOUT_FILENO, "  !!\n\n", 7);

    int returnchild = fork();

    if (returnchild < 0)
    {
        perror("fork() failed");
        exit(EXIT_FAILURE);
    }
    else if (returnchild == 0)
    {
        // child (new process)
        printf("Child of %d (%d) at play: %d\n", (int)pid, (int)getppid(), (int)getpid());
        waitcall = waitpid(-1, &status, 0);
        if (waitcall == -1)
        {
            perror("child - waitpid() failed");
            exit(EXIT_FAILURE);
        }
        printf("Wait return PID %d (status 0x%.4X)\n", waitcall, status);
        exit(EXIT_SUCCESS);
    }
    else
    {
        // parent goes down this path
        printf("Parent %d created child %d\n", (int)getpid(), returnchild);
        while ((waitcall = waitpid(-1, &status, 0)) != -1)
            printf("Parent waited for %d (status 0x%.4X)\n", waitcall, status);
        printf("Parent: all done\n");
    }
    return 0;
}

示例输出

程序名为wst13,其输出通过程序vis运行,使非打印字符可见。

$ wst13 | vis
child - waitpid() failed: No child processes
Hello World - I am parent:  \000\035@\000\000  !!

\000Child of 16413 (16413) at play: 16415
Parent 16413 created child 16415
Parent waited for 16415 (status 0x0100)
Parent: all done
$

改变了什么?

注意到变量fout was not setmelpomene,因此在第一次write()调用中使用它是不安全的。我用标准输出文件描述符STDOUT_FILENO的'官方'POSIX名称替换它,尽管使用1很有诱惑力。变量ppidcpid未被使用,因此它们也被删除了。

编写了else if (returnchild == 0)的操作。它会报告一些PID值,然后调用waitpid(),因为你的评论说它确实了 - 并且waitpid()失败了,因为孩子没有创建任何自己的孩子。

编写了else(父)进程的操作。它报告一些PID值,然后在循环中调用waitpid(),报告任何死孩子的PID和状态,并在没有更多孩子等待时退出循环。然后报告何时完成。

问题之一cited是第一个和第三个write()操作写入尾随空值,因为长度太长,因此包括终止空值。您可以在输出中看到这些内容:\000程序将其报告为vis。同样,中间write()打印pid的4个字节作为原始数据,从而产生字节序列\035@\000\000。当被视为小端整数的字节时,它相当于256 * 64 + 29 = 16413,这是pid中记录的值。

输出的排序在多核机器上是不确定的(在这种情况下,MacBook Pro中的Intel Core i7)。但是,在vis报告任何标准输出之前报告了孩子的错误(请参阅printf() anomaly after fork()。如果不使用| vis,示例输出如下:

$ wst13
Hello World - I am parent:  %@  !!

Parent 16421 created child 16422
Child of 16421 (16421) at play: 16422
child - waitpid() failed: No child processes
Parent waited for 16422 (status 0x0100)
Parent: all done
$

还有什么问题?

commented

  

请注意,最后一个write()将空字节输出到终端。中间write()打印4或8字节的二进制数据;那是不可读的。第一个write()也会向终端输出一个空字节。使用read()write()等低级I / O函数时,必须进行格式化,或使用POSIX函数dprintf()对文件描述符进行格式化(如与fprintf()等人的文件流相对。

解决这个问题的方法之一是:

    // write to terminal
    const char hw[] = "Hello World - I am parent:  ";
    const char nn[] = "  !!\n\n";
    if (write(STDOUT_FILENO, hw, sizeof(hw) - 1) != sizeof(hw) - 1 ||
        write(STDOUT_FILENO, (void *) & pid, sizeof(pid)) != sizeof(pid) ||
        write(STDOUT_FILENO, nn, sizeof(nn) - 1) != sizeof(nn) - 1)
    {
        perror("short write to standard output");
        exit(EXIT_FAILURE);
    }

仍然会为PID打印乱码。另一种选择是:

    // write to terminal
    const char hw[] = "Hello World - I am parent:  ";
    const char nn[] = "  !!\n\n";
    dprintf(STDOUT_FILENO, "%s%d%s", hw, (int)pid, nn);

有很多其他方法可以从中获得相同的输出。您可以修改write()的中间呼叫:

    // write to terminal
    const char hw[] = "Hello World - I am parent:  ";
    const char nn[] = "  !!\n\n";
    char pidstr[16];
    snprintf(pidstr, sizeof(pidstr), "%d", (int)pid);
    int pidlen = strlen(pidstr);
    if (write(STDOUT_FILENO, hw, sizeof(hw) - 1) != sizeof(hw) - 1 ||
        write(STDOUT_FILENO, pidstr, pidlen) != pidlen ||
        write(STDOUT_FILENO, nn, sizeof(nn) - 1) != sizeof(nn) - 1)
    {
        perror("short write to standard output");
        exit(EXIT_FAILURE);
    }

所以可能的补救措施仍在继续。你还能找到多少种方法呢?