QList <t> :: operator []中的ASSERT失败:&#34;索引超出范围&#34;

时间:2017-04-05 10:36:17

标签: c++ qt error-handling

我知道这个问题已经被多次询问了,我已经研究过,并且发现我的代码中的哪一部分给出了这个错误。我要求它为该解决方案提供替代方案。我正处理的情况是我连续收到一个大包。我已经连接了一个信号来读取如下的串行数据:

connect(&Serial, SIGNAL(readyRead()), this, SLOT(SerialRead()));

每当新的串行数据可供读取时,就会调用SerialRead()。我正在尝试读取长度不固定的数据包。现在发生的是SerialRead()读取几个字节的数据然后再次进行读取。由于数据包长度很大,因此无法在一次运行中读取完整的数据包。在我有完整的数据包之前,我无法进一步使用我的代码。幸运的是,我研究了数据包,发现数据包的第4个字节表示数据包的长度。所以现在我有了长度,这意味着我可以检查我是否按照第4个字节收到了完整的字节,然后再进一步移动。为此,我制作了以下代码:

QString serialData,numberOfBytes;
QStringList serialPacket;

void MainWindow::SerialRead()
{

  serialData.append(Serial.readAll());    //reading all the serial data
  serialPacket = serialData.split(" ");
  numberOfBytes = Convert.ToDec(serialPacket[3]);   //getting the length of the packer
  if(serialPacket.count() >= (numberOfBytes.toInt()))  //checking if all the bytes (full packet) is received or not
  {
      DisplayMessage(serialPacket);
  }
}

因此,当我收到完整数据包时,我会转到我的DisplayMessage函数来处理数据包。现在,当出现ASSERT Failure错误时,我注释掉了行numberOfBytes = Convert.ToDec(serialPacket[3]);及其余的代码,然后没有错误。所以我认为错误试图说明如果serialPacket [3]不包含任何数据那么它会给出错误。如果这是真的那么什么是它的替代品。任何人都可以告诉我一个检查是否收到完整数据包的好方法。感谢

编辑:

void MainWindow::SerialRead()
{
  serialData.append(Serial.readAll()); //Reading the data
  if(!serialData.isEmpty()) //Checking if data is empty or not
  {
    serialPacket = serialData.split(" ",QString::SkipEmptyParts);
    if(serialPacket.contains("CC")) //Checking if it contains "CC"
    {
    int index = serialPacket.indexOf("CC");
    numberOfBytes = Convert.ToDec(serialPacket[index+2]);
    if(serialPacket.count() >= ((numberOfBytes.toInt())+2))
    {
        DisplayMessage(serialPacket);
    }
    }
  }
}

2 个答案:

答案 0 :(得分:1)

如果在解析器的形式主义中使解析更加明确,解码器将表现得更好。双态机将完成这项工作。以下是完整的测试用例:

// https://github.com/KubaO/stackoverflown/tree/master/questions/packet-read-43228728
#include <QtTest>
#include <private/qringbuffer_p.h>

// See http://stackoverflow.com/a/32317276/1329652
/// A simple point-to-point intra-process pipe. The other endpoint can live in any
/// thread.
class AppPipe : public QIODevice {
   //...
};

class Decoder : public QObject {
   Q_OBJECT
   QPointer<QIODevice> m_device;
   QByteArray m_data;
   char m_first;
   bool m_isFirst = true;
   static constexpr char fromHex(char c) {
      return
            (c >= '0' && c <= '9') ? (c - '0') :
            (c >= 'A' && c <= 'F') ? (c - 'A' + 10) :
            (c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
            -1;
   }
   void decode(const QByteArray & src) {
      for (auto c : src) {
         auto val = fromHex(c);
         if (val < 0) continue;
         if (m_isFirst)
             m_first = val << 4;
         else
             m_data.append(m_first | val);
         m_isFirst = !m_isFirst;
      }
   }
   void onReadyRead() {
      // The data has the format "XX XX XX" where X are hex digits.
      // Spaces and invalid digits are skipped
      decode(m_device->readAll());
      if (m_data.size() >= 4) {
         auto length = 4 + m_data[3];
         if (m_data.size() >= length) {
            emit hasMessage(m_data.left(length));
            m_data.remove(0, length);
         }
      }
   }
public:
   Decoder(QIODevice * dev, QObject * parent = {}) : QObject{parent}, m_device{dev} {
      connect(dev, &QIODevice::readyRead, this, &Decoder::onReadyRead);
   }
   Q_SIGNAL void hasMessage(const QByteArray &);
};

class DecoderTest : public QObject {
   Q_OBJECT
   AppPipe src{nullptr, QIODevice::ReadWrite};
   AppPipe dst{&src, QIODevice::ReadWrite};
   Q_SLOT void initTestCase() {
      src.addOther(&dst);
   }
   Q_SLOT void test1() {
      Decoder dec(&dst, this);
      QSignalSpy spy(&dec, &Decoder::hasMessage);

      src.write("0"); // send a partial header
      QCOMPARE(spy.size(), 0);
      src.write("0 00 00 03 "); // send rest of the header
      QCOMPARE(spy.size(), 0);
      src.write("0A 0B "); // send partial data
      QCOMPARE(spy.size(), 0);
      src.write("0C "); // send rest of data
      QCOMPARE(spy.size(), 1);

      QCOMPARE(dst.bytesAvailable(), 0); // ensure all data has been read

      const QByteArray packet{"\x00\x00\x00\x03\x0A\x0B\x0C", 4+3};
      QCOMPARE(spy.first().size(), 1);
      QCOMPARE(spy.first().first(), {packet});
   }
   Q_SLOT void test2() {
      Decoder dec(&dst, this);
      QSignalSpy spy(&dec, &Decoder::hasMessage);

      src.write("BABE0004 C001 DA7E\n0FAB33"); // send a packet and part of another
      QCOMPARE(spy.size(), 1);
      src.write("01 AB\n");
      QCOMPARE(spy.size(), 2);

      QCOMPARE(spy.at(0).size(), 1);
      QCOMPARE(spy.at(1).size(), 1);
      const QByteArray packet1{"\xBA\xBE\x00\x04\xC0\x01\xDA\x7E", 4+4};
      const QByteArray packet2{"\x0F\xAB\x33\x01\xAB", 4+1};
      QCOMPARE(spy.at(0).first(), {packet1});
      QCOMPARE(spy.at(1).first(), {packet2});
   }
};

QTEST_GUILESS_MAIN(DecoderTest)
#include "main.moc"

答案 1 :(得分:1)

正如其他用户的评论中所提到的,您必须确保您尝试接收的数据包在第4个索引处有一些数据。这样您就可以进一步处理它来计算长度。正如你所说serialPacket的第四个索引将包含长度,你必须设置一些条件,即串行数据包的大小包含至少4或5个字节。类似的东西:

    if(serialPacket.size()>=5)
    {
        numberOfBytes = Convert.ToDec(serialPacket[3]);
    }
    else
    {
        QMessageBox MessageBox;
        MessageBox.setText("Error receving packets");
    }