【问题标题】:Writing my own shell, undeclared identifier "output"编写我自己的外壳,未声明的标识符“输出”
【发布时间】:2018-11-12 17:06:58
【问题描述】:

这是我的代码,用于我自己的 C 语言 shell。编译时出现错误:使用未声明的标识符“输出”。以下是编译时的一些错误示例:

错误:使用未声明的标识符“输出”字符 输入[100];输出[100];

test3.c:53:15:错误:使用未声明的标识符“输出” strcpy(输出,args[i+1]); ^

test3.c:53:15: 错误:使用未声明的标识符“输出”

test3.c:60:8: 警告:函数“open”的隐式声明是 在 C99 中无效 [-Wimplicit-function-declaration] j = open(input, O_RDONLY, 0); ^

test3.c:60:20: 错误:使用未声明的标识符 'O_RDONLY' j = 打开(输入,O_RDONLY,0); ^

test3.c:61:29:错误:使用未声明的标识符“O_RDONLY” if ((j = open(input, O_RDONLY, 0))

test3.c:70:12: 警告:函数 'creat' 的隐式声明是 无效 C99 [-Wimplicit-function-declaration] if ((i= creat(output , 0644))

test3.c:70:18: 错误:使用未声明的标识符“输出” if ((i= 创建(输出,0644))

这是我的代码:

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "signal.h"
#include "unistd.h"

void prompt(char*);
void execute( char* );
char** parse( char* );

int main( int ac, char* av[] )
{
  char input[255]; // buffer for supporting command

  signal( SIGINT, SIG_IGN ); // ignore ctrl-c

  while(1)
  {
    prompt(input);
    execute( input );
  }
};

void execute( char* str)
{
  int fork_result, status, i = 0,j=0,in=0,out=0;
  char input[100];output[100];
  char** args = parse( str ); // splits the user command into arguments

  fork_result = fork(); // attempt to fork
  if ( fork_result == -1 ) // failure
  {
    perror("Failed to fork\n");
    exit(1);
  }
  else if ( fork_result == 0 ) // I'm the child
  {
    for(i=0;args[i]!='\0';i++)
    {
      if(strcmp(args[i],"<")==0)
      {   
        args[i]=NULL;
        strcpy(input,args[i+1]);
        in=2;   
      }   
      if(strcmp(args[i],">")==0)
      {
        args[i]=NULL;
        strcpy(output,args[i+1]);
        out=2;
      }   
    }

    if (in) 
    {
      j = open(input, O_RDONLY, 0);
      if ((j = open(input, O_RDONLY, 0)) < 0) 
      {
        perror("Couldn't open input file");
        exit(0);
      }
      dup2(j, 0);
      close(j);
    }

    if (out) 
    {
      if ((i= creat(output , 0644)) < 0) 
      {
        perror("Couldn't open the output file");
        exit(0);
      }
      dup2(i, STDOUT_FILENO);
      close(i);
    }

    execvp( args[0], args );
    perror("failed to exec\n");
    exit(2);
  }
  else // I'm the parent
  {
    // wait here
    wait(&status); // wait for child to finish
    free( args ); // free dynamic memory
  }
}

char** parse( char* str )
{
  char** args = malloc( 256 );
  int i = 0;

  args[i] = strtok( str, " " );

  while( args[i] )
  {
    i++;
    args[i] = strtok( NULL, " " );
  }

  return args;
}

void prompt(char* input)
{
  printf("$ "); // print prompt
  fgets( input, 255, stdin );

  input[strlen(input)-1] = '\0'; // overwrite \n with \0

  if ( strcmp( input, "exit" ) == 0 ) // shell command
    exit(0);
}

【问题讨论】:

  • getopt 这样的东西存在时,为什么要编写自己的选项解析?

标签: c linux shell unix


【解决方案1】:

char input[100];output[100];

你想要:

char input[100], output[100];

另加:#include &lt;fcntl.h&gt;

一般来说,man open(和您使用的其他功能)是您的朋友——它会告诉您要添加什么 #includes。

您的代码中还有更多潜在的错误和任意限制。一些例子:

void execute( char* str)
{
  char input[100], output[100];
  ...
  if(strcmp(args[i],"<")==0)
  {   
    args[i]=NULL;
    strcpy(input,args[i+1]);  // possible stack buffer overflow.

  if(strcmp(args[i],">")==0)
  {
    args[i]=NULL;
    strcpy(output,args[i+1]);  // possible stack buffer overflow


char** parse( char* str )
{
  char** args = malloc( 256 );  // limit of 256/sizeof(char*) parameters.
  // on a 64-bit system, if more than 32 parameters are supplied ...

         args[i] = strtok( NULL, " " );  // ... possible heap buffer overflow.


  fgets( input, 255, stdin );  // arbitrary limit of 254 characters on command line.

不保证字符串以\n结尾:

  input[strlen(input)-1] = '\0'; // overwrite \n with \0

如果我给这个“外壳”评分,我会给它一个“F”。

【讨论】:

    【解决方案2】:

    您的代码中有多个错误。

    1. 在第 27 行,您需要用逗号而不是分号 char input[100], output[100]; 分隔输入和输出的两个变量定义,或者指定输出类型,如 char input[100]; char output[100]; 您已经完成这已经在上面的行中了。

    2. 编译器抱怨缺少函数open 和标识符O_RDONLY 的定义。这可以通过在文件顶部添加 #include "fcntl.h" 来解决。

    在这些更改之后,代码对我来说编译得很好(使用 gcc 5.4.0):

    #include "stdio.h"
    #include "stdlib.h"
    #include "string.h"
    #include "signal.h"
    #include "unistd.h"
    #include "fcntl.h"
    
    void prompt(char*);
    void execute( char* );
    char** parse( char* );
    
    int main( int ac, char* av[] )
    {
      char input[255]; // buffer for supporting command
    
      signal( SIGINT, SIG_IGN ); // ignore ctrl-c
    
      while(1)
      {
        prompt(input);
        execute( input );
      }
    };
    
    void execute( char* str)
    {
      int fork_result, status, i = 0,j=0,in=0,out=0;
      char input[100], output[100];
      char** args = parse( str ); // splits the user command into arguments
    
      fork_result = fork(); // attempt to fork
      if ( fork_result == -1 ) // failure
      {
        perror("Failed to fork\n");
        exit(1);
      }
      else if ( fork_result == 0 ) // I'm the child
      {
        for(i=0;args[i]!='\0';i++)
        {
          if(strcmp(args[i],"<")==0)
          {   
            args[i]=NULL;
            strcpy(input,args[i+1]);
            in=2;   
          }   
          if(strcmp(args[i],">")==0)
          {
            args[i]=NULL;
            strcpy(output,args[i+1]);
            out=2;
          }   
        }
    
        if (in) 
        {
          j = open(input, O_RDONLY, 0);
          if ((j = open(input, O_RDONLY, 0)) < 0) 
          {
            perror("Couldn't open input file");
            exit(0);
          }
          dup2(j, 0);
          close(j);
        }
    
        if (out) 
        {
          if ((i= creat(output , 0644)) < 0) 
          {
            perror("Couldn't open the output file");
            exit(0);
          }
          dup2(i, STDOUT_FILENO);
          close(i);
        }
    
        execvp( args[0], args );
        perror("failed to exec\n");
        exit(2);
      }
      else // I'm the parent
      {
        // wait here
        wait(&status); // wait for child to finish
        free( args ); // free dynamic memory
      }
    }
    
    char** parse( char* str )
    {
      char** args = malloc( 256 );
      int i = 0;
    
      args[i] = strtok( str, " " );
    
      while( args[i] )
      {
        i++;
        args[i] = strtok( NULL, " " );
      }
    
      return args;
    }
    
    void prompt(char* input)
    {
      printf("$ "); // print prompt
      fgets( input, 255, stdin );
    
      input[strlen(input)-1] = '\0'; // overwrite \n with \0
    
      if ( strcmp( input, "exit" ) == 0 ) // shell command
        exit(0);
    }
    

    【讨论】: