从命令行读取()returns EISDIR 错误

read() from command line returns EISDIR error

我正在尝试从终端读取箭头键字符,并使用它通过 ROS 发送 String 类型的消息。为此,我使用了 termios read() 函数。

首先,我做了一个小测试,在 C 下运行良好,使用 gcc 编译。这是代码:

#include <unistd.h>
#include <stdlib.h>
#include <termios.h> // for keyboard input
#include <string.h>
#include <stdio.h>

bool quit_requested = false;

void processKeyboardInput (char c)
{
   switch (c)
   {
     case 68:// Left arrow pressed
     {
       puts("Left pressed");
       break;
     }
     case 67://Right arrow pressed
     {
       puts("Right pressed");
       break;
     }
     case 65://Up arrow pressed
     {
       puts("Up pressed");
       break;
     }
     case 66://Down arrow pressed
     {
       puts("Down pressed");
       break;
     }
     case 'q'://Quit arrow pressed
     {
       quit_requested = true;
       puts("q pressed, quitting...");
     }
     default:
     {
       break;
     }
 }

}

int main(int argc, char const *argv[]) {
  int key_file_descriptor;
  struct termios raw;
  struct termios original_terminal_state;

  tcgetattr(key_file_descriptor, &original_terminal_state); // get       terminal properties
  memcpy(&raw, &original_terminal_state, sizeof(struct termios));

  raw.c_lflag &= ~(ICANON | ECHO);//local modes, enable canonical mode and echo
  // Setting a new line, then end of file
  raw.c_cc[VEOL] = 1;//special characters
  raw.c_cc[VEOF] = 2;
  tcsetattr(key_file_descriptor, TCSANOW, &raw);

  puts("Reading from keyboard");
  puts("---------------------------");
  puts("Press the arrow keys to move and q to quit");

  char c;
  while (!quit_requested)
  {
    if (read(key_file_descriptor, &c, 1) < 0)
    {
      perror("read char failed():");
      exit(-1);
    }
    processKeyboardInput(c);
  }
      tcsetattr(key_file_descriptor, TCSANOW,      &original_terminal_state);
      puts("Exit");
    return 0;
    }

完成此操作后,我添加了 ROS 内容以使用 String 消息发送密钥:

#include <unistd.h>
#include <termios.h> // for keyboard input
#include <cstring>
#include <stdio.h>

#include "ros/ros.h"
#include "std_msgs/String.h"


bool quit_requested = false;


std::string processKeyboardInput (char c)
{

   switch (c)
   {
     case 68:// Left arrow pressed
     {
       puts("Left pressed");
       return ("left");
     }
     case 67://Right arrow pressed
     {
       puts("Right pressed");
       return ("right");
     }
     case 65://Up arrow pressed
     {
       puts("Up pressed");
       return ("forward");
     }
     case 66://Down arrow pressed
     {
       puts("Down pressed");
       return ("backward");
     }
     case 'q'://Quit arrow pressed
     {
       quit_requested = true;
       puts("q pressed, quitting...");
     }
     default:
     {
       return ("");
     }
 }

}

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

  std::string cmd;
  int key_file_descriptor;
  char c;
  int error;
  struct termios raw;
  struct termios original_terminal_state;
  //std::string name = "key_teleop";

  /**** INIT ROS STUFFS  *****/
  ros::init(argc, argv, "key_teleop");
  std_msgs::String msg;
  ros::NodeHandle n;
  ros::Publisher key_pub = n.advertise<std_msgs::String>("key_teleop", 1000);
  ros::Rate loop_rate(1);
  /***************************/

  tcgetattr(key_file_descriptor, &original_terminal_state); // get terminal properties
  memcpy(&raw, &original_terminal_state, sizeof(struct termios));

  raw.c_lflag &= ~(ICANON | ECHO);//local modes, enable canonical mode and echo
  // Setting a new line, then end of file
  raw.c_cc[VEOL] = 1;//special characters
  raw.c_cc[VEOF] = 2;
  tcsetattr(key_file_descriptor, TCSANOW, &raw);

  puts("Reading from keyboard");
  puts("---------------------------");
  puts("Press the arrow keys to move and q to quit");


  while (ros::ok() & (!quit_requested))
  {
  //if (read(key_file_descriptor, &c, 1) < 0)
    error = read(key_file_descriptor, &c, 1);
    if ( error < 0)//Process the error
    {//TODO I get errors, not ROSify code doesn't, C / C++ code mixture issue??
      if (error == EAGAIN)
        puts ("EAGAIN");
      else if (error == EBADF)
        puts ("EBADF");
      else if (error == EFAULT)
        puts ("EFAULT");
      else if (error == EINTR)
        puts ("EINTR");
      else if (error == EINVAL)
        puts ("EINVAL");
      else if (error == EIO)
        puts ("EIO");
      else if (error = EISDIR)
        puts ("EISDIR");
      perror("read char failed():");
      exit(-1);
    }
    cmd = processKeyboardInput(c);
    if (!cmd.empty())
    {
      msg.data = cmd;
      key_pub.publish(msg);
      ros::spinOnce();
      //loop_rate.sleep();
    }
  }
  tcsetattr(key_file_descriptor, TCSANOW, &original_terminal_state);
  puts("Exit");
return 0;
}

创建 CMakeLists.txtpackage.xml 后,我使用 catkin_make 进行了编译。测试它现在不起作用,大多数时候我在 read() 收到错误 return,它进入 EISDIR 案例并打印它。知道为什么我现在收到此错误,而之前的 c 示例运行正常吗?

提前致谢!

根据@Jonathan 的推荐,我将标志 -Wall -Werror -Wextra 添加到 CMake 编译标志中,发现编译器抛出的下一条消息:

error: ‘key_file_descriptor’ may be used uninitialized in this function [-Werror=maybe-uninitialized]

我找到了这个 nice article 并更改了我用于 STDIN_FILENOint key_file_descriptor。所以我已经在整个代码中替换了它,现在可以正常工作了!我也删除了比较错字。谢谢大家!