[QByteArray] '\0' characters at the end of the data are discarded

  • Hello,

    I found a bug in my application the other day which took me some time to find the cause.

    Basically, I'm using the QByteArray class to construct commands that I send over UART. Those commands are just an array of bytes that complies with some home-made protocol. In some cases, one of those commands has its last two bytes set to zero. What I was seeing is that the last two bytes were never sent over the serial line.

    I finally found that it was caused by the QByteArray copy constructor which basically discards the ending '\0's. The Qt documentation does say that QByteArray silently adds a '\0' to terminate the data, so after reading this, I understood my bug.

    However, I'm still a bit surprised of this implementation. How can this class be called QByteArray, and make an assumption on the last data byte non being zero? To me, this should just be a wrapper around a C array and certainly not interpret the data I put in it.

    I would like your point of view on this and also a possible way to workaround it. I'm quite worried now that some weird bug may appear because a QByteArray is used here and there and that some of my data silently disappears!

    Thanks in advance.

  • I also had the same problem, but the way I worked around this was to make use of the constructor that takes the size of the data (this was for TCP/IP comms though). Look at the "Description":http://qt-project.org/doc/qt-5/qbytearray.html#details of QByteArray, they mention that issue "A QByteArray can embed '\0' bytes".

    Something like :
    QByteArray myArray1("1234\0\0", 6);

    From the documentation (what you might be interested in in your application):
    const char cart[] = {'c', 'a', '\0', 'r', '\0', 't'};
    QByteArray ba4(QByteArray::fromRawData(cart, 6));
    ba4.size(); // Returns 6.
    ba4.constData(); // Returns "ca\0r\0t" without terminating \0.

    This should make sure that the array is working correctly. Also when transmitting the data, either specify the number of bytes to transmit (aka myArray1.size()), or check how many bytes were transmitted. Most transmit functions have both these options. They should work correctly if the size of the QByteArray is correct though. Transmitters normally respect the size, not the data (from my understanding and experience, I might be wrong).

    Hope this helps.


    [edit: added the example from the QByteArray documentation]

  • Moderators

    Just use the QByteArray::data() function to get the raw data, null terminated. "Link":http://qt-project.org/doc/qt-5/qbytearray.html#data.

  • Badger:
    Thanks for your reply. Yes, this is what I ended up doing. As you said, the only way to guarantee that I get all the raw data, I have to use the constructor QByteArray(const char * data, int size = -1) which will copy exactly the number of bytes I want.

    I do not quite agree. If you use QByteArray::data(), at some point, you will need to know the size of the raw data.

    Try the code below:

    • the iteration at the end is OK (I know the size of data returned by data() and iterate all over it)
    • but third is typical example where you cannot guarantee that all your data have been copied to the new object. And it is so easily written!

    @#include <QCoreApplication>

    int main(int argc, char *argv[])
    QCoreApplication a(argc, argv);

    QByteArray first("1234\0\0", 6);
    qDebug("first.size()=%d", first.size());

    QByteArray second(first.data(), first.size());
    qDebug("second.size()=%d", second.size());

    QByteArray third(first.data());
    qDebug("third.size()=%d", third.size());

    char *data = first.data();
    int size = first.size()+1;
    for (int i = 0; i < size; i++)
    qDebug("%d:'%c'", i, *(data+i));

    return a.exec();

Log in to reply

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.