C 管道、子进程和子进程的范围

C 管道、子进程和子进程的范围,c,unix,concurrency,pipe,fork,C,Unix,Concurrency,Pipe,Fork,我在一个操作系统课程,我有一个关于分叉和管道的项目。在我开始我的项目之前,我试图更好地理解分叉和管道,所以我正在研究一个示例。这就是所讨论的代码(当pid=fork()等于0且为子进程时,情况0): { 案例1: 佩罗(“fork call”); 出口(2); 打破 案例0: 字符str1[MSGSIZE]; 字符str2[MSGSIZE]; 字符str3[MSGSIZE]; printf(“输入字符串!”); fgets(str1、MSGSIZE、stdin); printf(“输入另一个字符

我在一个操作系统课程,我有一个关于分叉和管道的项目。在我开始我的项目之前,我试图更好地理解分叉和管道,所以我正在研究一个示例。这就是所讨论的代码(当pid=fork()等于0且为子进程时,情况0):

{

案例1:
佩罗(“fork call”);
出口(2);
打破
案例0:
字符str1[MSGSIZE];
字符str2[MSGSIZE];
字符str3[MSGSIZE];
printf(“输入字符串!”);
fgets(str1、MSGSIZE、stdin);
printf(“输入另一个字符串!”);
fgets(str2、MSGSIZE、stdin);
printf(“输入最后一个字符串!”);
fgets(str3、MSGSIZE、stdin);
接近(p[0]);
写入(p[1],msg1,MSGSIZE);
写入(p[1],msg2,MSGSIZE);
写入(p[1],msg3,MSGSIZE);
printf(“即将写入str1、str2、str3…\n”);
写入(p[1],str1,MSGSIZE);
写入(p[1],str2,MSGSIZE);
写入(p[1],str3,MSGSIZE);
打破
违约:
关闭(p[1]);
对于(j=0;j<6;j++)
{
读取(p[0],inbuf,MSGSIZE);
printf(“%s\n”,inbuf);
}
等待(空);
}//开关
在命令行上编译时,会出现以下错误:

$gcc-o p3管道3.c

pipe3.c:45:7:错误:应为表达式 字符str1[MSGSIZE]; ^

pipe3.c:49:13:错误:使用未声明的标识符“str1” fgets(str1、MSGSIZE、stdin); ^

pipe3.c:62:19:错误:使用未声明的标识符“str1” 写入(p[1],str1,MSGSIZE); ^

产生了3个错误

我最初在main函数的开头声明了str1、str2和str3(我知道此时这仍然是父进程),在编译时没有得到这些错误。我试图在子进程中声明这些内容的唯一原因是因为我试图理解子进程的范围以及它的功能,这意味着我只是在尝试和思考什么是合法的,什么是非法的。我真的不明白为什么编译器关心子进程是创建和初始化变量的进程,然后只在子进程的范围内使用它们来写入管道。所以我想我想问的主要问题是,这实际上是管道的限制吗?我尝试使用char*str1;在子进程中,然后使用fgets存储输入,但我仍然得到相同的编译器错误。另外,我是否错误地认为子进程的范围只是介于案例0和break之间的代码;或者,子进程是否获得父程序的完整副本,即忽略父进程中的其余代码,因为子进程执行代码的唯一时间是在pid==0时?我知道这可能是一些基本的东西,但操作系统是让我作为一名程序员彻底困惑的第一门课程

以下是关于上下文和完整性的完整源代码:

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

#define MSGSIZE 16
int main(int argc, char *argv[])
{
  char inbuf[MSGSIZE];
  char *msg1 = "Hello world #1";
  char *msg2 = "Hello world #2";
  char *msg3 = "Hello world #3";
  char str1[MSGSIZE]; 
  char str2[MSGSIZE]; 
  char str3[MSGSIZE];

  int  p[2], j;
  pid_t pid;    

  if(pipe(p) == -1)
  {
    perror("pipe call");
    exit(1);
  }

  switch(pid = fork())
  {

case -1:

  perror("fork call");
  exit(2);
  break;
case 0:
  //char *str1; 
  //char *str2; 
  //char *str3;
  printf("Enter a string! ");
  fgets(str1, MSGSIZE, stdin);
  printf("Enter another string! ");
  fgets(str2, MSGSIZE, stdin);

  printf("Enter the last string! ");
  fgets(str3, MSGSIZE, stdin);


  close(p[0]);
  write(p[1], msg1, MSGSIZE);
  write(p[1], msg2, MSGSIZE);
  write(p[1], msg3, MSGSIZE);
  printf("About to write the input strings...\n");
  write(p[1], str1, MSGSIZE);
  write(p[1], str2, MSGSIZE);
  write(p[1], str3, MSGSIZE);
  break;
default:
  close(p[1]);
  for(j = 0; j < 6; j++)
  {
    read(p[0], inbuf, MSGSIZE);
    printf("%s\n", inbuf);
  }
  wait(NULL);   

  }//switch

  return 0;
}
#包括
#包括
#包括
#定义MSGSIZE 16
int main(int argc,char*argv[])
{
char inbuf[MSGSIZE];
char*msg1=“你好,世界1”;
char*msg2=“你好,世界2”;
char*msg3=“你好,世界3”;
字符str1[MSGSIZE];
字符str2[MSGSIZE];
字符str3[MSGSIZE];
int p[2],j;
pid_t pid;
如果(管道(p)=-1)
{
佩罗尔(“管道呼叫”);
出口(1);
}
开关(pid=fork())
{
案例1:
佩罗(“fork call”);
出口(2);
打破
案例0:
//char*str1;
//char*str2;
//char*str3;
printf(“输入字符串!”);
fgets(str1、MSGSIZE、stdin);
printf(“输入另一个字符串!”);
fgets(str2、MSGSIZE、stdin);
printf(“输入最后一个字符串!”);
fgets(str3、MSGSIZE、stdin);
接近(p[0]);
写入(p[1],msg1,MSGSIZE);
写入(p[1],msg2,MSGSIZE);
写入(p[1],msg3,MSGSIZE);
printf(“即将写入输入字符串…\n”);
写入(p[1],str1,MSGSIZE);
写入(p[1],str2,MSGSIZE);
写入(p[1],str3,MSGSIZE);
打破
违约:
关闭(p[1]);
对于(j=0;j<6;j++)
{
读取(p[0],inbuf,MSGSIZE);
printf(“%s\n”,inbuf);
}
等待(空);
}//开关
返回0;
}

编译器对进程一无所知。它只关心牙套。您之所以会出现错误,是因为您处于c89模式,其中变量必须在作用域的开头声明(请注意,
case
不会打开作用域)

尝试将
案例0
的全部内容放入一个块中,或将
-std=c99
选项传递给编译器。

标准C(c99之前)需要在一个块的开头声明变量。函数(包括
main
)在这个意义上是一个集团

开关
可以是块,但
案例
不是块,因此不能在案例中声明新变量。真正的错误在
char str1[MSGSIZE],因此未声明导致其他两个错误的原因

如果只想在子对象中声明变量(对程序员来说有意义,但对编译器来说没有意义:
fork
只是它的一个函数),可以通过两种方式来实现:

  • 一个干净的方法是将其放入函数中并调用该函数:

    void doCopy(int *p) {
      char str1[MSGSIZE]; 
      char str2[MSGSIZE]; 
      char str3[MSGSIZE];
      printf("Enter a string! ");
      fgets(str1, MSGSIZE, stdin);
      printf("Enter another string! ");
      fgets(str2, MSGSIZE, stdin);
    
      printf("Enter the last string! ");
      fgets(str3, MSGSIZE, stdin);
    
    
      close(p[0]);
      write(p[1], msg1, MSGSIZE);
      write(p[1], msg2, MSGSIZE);
      write(p[1], msg3, MSGSIZE);
      printf("About to write the input strings...\n");
      write(p[1], str1, MSGSIZE);
      write(p[1], str2, MSGSIZE);
      write(p[1], str3, MSGSIZE);
    }
    
    int main(int argc, char *argv[])
    ...
            case 0:
                doCopy(p, MSGSIZE);
                break;
    ...
    
  • 一种不太惯用但可编译的方法是,在以下情况下,强制使用虚拟对象创建bloc:


噢,哇,我从未意识到这一点。我开始觉得我错过了一些关于叉子或过程的主要内容哈哈。非常感谢你,我真的很感谢你的帮助!嘿,非常感谢你的帮助!这很有道理。我尝试将案例0中的代码推送到它自己的范围内,结果成功了。这个函数肯定也是一个更好的方法。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define MSGSIZE 16
int main(int argc, char *argv[])
{
  char inbuf[MSGSIZE];
  char *msg1 = "Hello world #1";
  char *msg2 = "Hello world #2";
  char *msg3 = "Hello world #3";
  char str1[MSGSIZE]; 
  char str2[MSGSIZE]; 
  char str3[MSGSIZE];

  int  p[2], j;
  pid_t pid;    

  if(pipe(p) == -1)
  {
    perror("pipe call");
    exit(1);
  }

  switch(pid = fork())
  {

case -1:

  perror("fork call");
  exit(2);
  break;
case 0:
  //char *str1; 
  //char *str2; 
  //char *str3;
  printf("Enter a string! ");
  fgets(str1, MSGSIZE, stdin);
  printf("Enter another string! ");
  fgets(str2, MSGSIZE, stdin);

  printf("Enter the last string! ");
  fgets(str3, MSGSIZE, stdin);


  close(p[0]);
  write(p[1], msg1, MSGSIZE);
  write(p[1], msg2, MSGSIZE);
  write(p[1], msg3, MSGSIZE);
  printf("About to write the input strings...\n");
  write(p[1], str1, MSGSIZE);
  write(p[1], str2, MSGSIZE);
  write(p[1], str3, MSGSIZE);
  break;
default:
  close(p[1]);
  for(j = 0; j < 6; j++)
  {
    read(p[0], inbuf, MSGSIZE);
    printf("%s\n", inbuf);
  }
  wait(NULL);   

  }//switch

  return 0;
}
void doCopy(int *p) {
  char str1[MSGSIZE]; 
  char str2[MSGSIZE]; 
  char str3[MSGSIZE];
  printf("Enter a string! ");
  fgets(str1, MSGSIZE, stdin);
  printf("Enter another string! ");
  fgets(str2, MSGSIZE, stdin);

  printf("Enter the last string! ");
  fgets(str3, MSGSIZE, stdin);


  close(p[0]);
  write(p[1], msg1, MSGSIZE);
  write(p[1], msg2, MSGSIZE);
  write(p[1], msg3, MSGSIZE);
  printf("About to write the input strings...\n");
  write(p[1], str1, MSGSIZE);
  write(p[1], str2, MSGSIZE);
  write(p[1], str3, MSGSIZE);
}

int main(int argc, char *argv[])
...
        case 0:
            doCopy(p, MSGSIZE);
            break;
...
...
  switch(pid = fork())
  {

case -1:

  perror("fork call");
  exit(2);
  break;
case 0:
  if(1) {
      char str1[MSGSIZE]; 
      char str2[MSGSIZE]; 
      char str3[MSGSIZE];
      printf("Enter a string! ");
      fgets(str1, MSGSIZE, stdin);
      printf("Enter another string! ");
      fgets(str2, MSGSIZE, stdin);

      printf("Enter the last string! ");
      fgets(str3, MSGSIZE, stdin);


      close(p[0]);
      write(p[1], msg1, MSGSIZE);
      write(p[1], msg2, MSGSIZE);
      write(p[1], msg3, MSGSIZE);
      printf("About to write the input strings...\n");
      write(p[1], str1, MSGSIZE);
      write(p[1], str2, MSGSIZE);
      write(p[1], str3, MSGSIZE);
  }
  break;
default:
...