Results 1 to 15 of 15

Thread: [ SOLVED (kinda) ]copy structure to QByteArray

  1. #1
    Join Date
    Jan 2008
    Posts
    107
    Thanks
    36
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Red face [ SOLVED (kinda) ]copy structure to QByteArray

    Hi,

    I'm trying to copy this structure to a QByteArray:

    Qt Code:
    1. typedef struct
    2. {
    3. quint32 status_change_id;
    4. bool result_code; // true if sucessful, false otherwise
    5. quint8 reserved[3]; /* Set to 0 */
    6. } driver_id_receipt_data_type;
    To copy to clipboard, switch view to plain text mode 

    The structure already being declared and filled with:

    Qt Code:
    1. driver_id_receipt_data_type receipt;
    2. receipt.status_change_id = payload.mid(2,4).toUInt();
    3. receipt.result_code = true;
    4. receipt.reserved[0] = 0;
    5. receipt.reserved[1] = 0;
    6. receipt.reserved[2] = 0;
    To copy to clipboard, switch view to plain text mode 

    Every approach I use (cast to (char *), ::fromRawData(), etc) I stumble upon the impossibility of reaching the desired goal...

    Is there a way of doing this?

    Any help appreciated
    Best regards,
    Pedro Doria Meunier
    Last edited by pdoria; 13th October 2009 at 14:07. Reason: SOLVED (kinda)

  2. #2
    Join Date
    Dec 2006
    Posts
    849
    Thanks
    6
    Thanked 162 Times in 151 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: copy structure to QByteArray

    show us what you tried and elaborate on how you want to use that QByteArray - and in what way did those failures manifest themselves?

  3. #3
    Join Date
    Jan 2008
    Posts
    107
    Thanks
    36
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: copy structure to QByteArray

    Hi Caduel,

    Thx for your time.

    The goal here is simply put those bytes of the structure into a QByteArray which will then be passed to another function to process it.

    Since I have a gadzillion of other struct types I can't possibly write a function to handle them one-by-one. I need a standard way of passing data to the receiving function. Hence the QByteArray ...

    As requested here's an early example of trying to copy the data into the QByteArray:

    Qt Code:
    1. QByteArray packet;
    2. memcpy(packet.data(), &receipt, sizeof(receipt) );
    To copy to clipboard, switch view to plain text mode 

    Even this old school, deprecated method, fails miserably ...

    BR,
    Pedro Doria Meunier

  4. #4
    Join Date
    Jan 2008
    Posts
    107
    Thanks
    36
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: copy structure to QByteArray

    Anyone?

    Pls, I'm really stuck with this ...

  5. #5
    Join Date
    Oct 2009
    Posts
    8
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: copy structure to QByteArray

    Firstly, I am not familiar with QByteArray. However, clearly you need to ensure that the array within QByteArray is large enough to fit your structure. A cursory glance of the QByteArray documentation would remind you of this and how to do it. Once you have actually allocated your destination buffer, I see no reason why memcpy would not work.

    Having said that, I suspect this is a solution to a problem that shouldn't exist in the first place. However, you haven't provided enough detail to be sure.

    Edit: QDataStream would probably do the job too.
    Last edited by jord; 13th October 2009 at 14:12.

  6. #6
    Join Date
    Jan 2008
    Posts
    107
    Thanks
    36
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Lightbulb Re: copy structure to QByteArray

    First off many thanks to all that have replied!

    Here's my (convoluted) solution:

    Qt Code:
    1. driver_id_receipt_data_type *receipt = new driver_id_receipt_data_type;
    2. receipt->status_change_id = payload.mid(2,4).toUInt();
    3. receipt->result_code = true;
    4. receipt->reserved[0] = 0;
    5. receipt->reserved[1] = 0;
    6. receipt->reserved[2] = 0;
    7.  
    8. char *p = (char*)receipt; // cast it to char* to make a QByteArray
    9. QByteArray packet(p, sizeof(driver_id_receipt_data_type));
    To copy to clipboard, switch view to plain text mode 

    QByteArray packet now holds the receipt data...

    Knowing this a very convoluted way of doing things, I'd love to see a simpler, more direct, approach to reach the above goal...

    BR,
    Pedro Doria Meunier

  7. #7
    Join Date
    Dec 2006
    Posts
    849
    Thanks
    6
    Thanked 162 Times in 151 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: [ SOLVED (kinda) ]copy structure to QByteArray

    two lines of code is not that convoluted, is it?

  8. #8
    Join Date
    Jul 2008
    Posts
    426
    Thanks
    9
    Thanked 55 Times in 53 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: [ SOLVED (kinda) ]copy structure to QByteArray

    Hi, you could use QDataStream to write every single member of your struct to a QByteArray. That would get rid of the cast, but you would have to adjust the code each time you change your struct. It will also require more lines of code and probably be slower than your current version.

    Ginsengelf

  9. #9
    Join Date
    Oct 2009
    Posts
    8
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: [ SOLVED (kinda) ]copy structure to QByteArray

    Hi pdoria,

    I would like to discourage you from serializing an object by doing a byte-by-byte copy (which is what you are doing here), explain why, and offer some advice. What you are doing may be fine for your application (only you know), but it is very easy to shoot yourself in the foot with this approach. Worse still, depending on what is in your objects, you may cause your application to crash in a completely unrelated piece of code, making it a nightmare to track down the problem.


    You need to be wary of the following things with this approach:

    1. The object's copy constructor is not called.

    This means the copy constructor is also not called for any objects that are contained within your structs. This is disastrous for objects that allocate memory on the heap. Problems include:
    • The original object and its copy interfering with one another and trashing their internal data structures.
    • One of the objects getting destroyed, leaving the other with invalid pointers that it continues to use.
    • Double frees of memory once both objects are destroyed, resulting in the heap getting trashed.


    2. How the data is arranged in the struct and the padding between data items is compiler dependent.

    If you are serializing the object with the intent of saving it to disk or sharing it with another party, be aware that different compilers and compiler settings may arrange the data in the struct differently. Hence this can fail unexpectedly.


    3. Different computer architectures have different constraints on how data is represented.

    Different computer architectures can have different endianness and different memory alignment requirements. As with point 2 above, this can cause issues when sharing the serialized object with another party.


    A better approach is to write functions that explicitly serialize and deserialize the objects. It is more work initially, but it is robust against future changes and can avoid subtle and hard to track down errors in the future. The book 'C++ GUI Programming with Qt 4' has a section that touches on this. You can find a legit pdf of the first edition here: http://www.qtrac.eu/marksummerfield.html. The section is 'Reading and Writing Binary Data', on p.274 of this ebook.

    The general approach is to add functions like the following to your structs/classes (note I haven't tested this):

    Qt Code:
    1. QByteArray serialize()
    2. {
    3. QByteArray byteArray;
    4.  
    5. QDataStream stream(&byteArray, QIODevice::WriteOnly);
    6. stream.setVersion(QDataStream::Qt_4_5);
    7.  
    8. stream << status_change_id
    9. << result_code
    10. << reserved[0]
    11. << reserved[1]
    12. << reserved[2];
    13.  
    14. return byteArray;
    15. }
    16.  
    17. void deserialize(const QByteArray& byteArray)
    18. {
    19. QDataStream stream(byteArray);
    20. stream.setVersion(QDataStream::Qt_4_5);
    21.  
    22. stream >> status_change_id
    23. >> result_code
    24. >> reserved[0]
    25. >> reserved[1]
    26. >> reserved[2];
    27. }
    To copy to clipboard, switch view to plain text mode 

    Good luck,

    Jord

  10. The following user says thank you to jord for this useful post:

    pdoria (15th October 2009)

  11. #10
    Join Date
    Jan 2008
    Posts
    107
    Thanks
    36
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Thumbs up Re: [ SOLVED (kinda) ]copy structure to QByteArray

    Jord,

    I can only say this is one HECK of a good advice! THANK YOU!

    It reminded me that I have to step out of pure C thinking ...

    Now about the versioning ...
    I believe I can't do it because that would insert the "magic numbers" in the stream's header, right?

    I'm dealing with a protocol that doesn't have room for "extra info" ...

    Best regards,
    Pedro Doria Meunier

  12. #11
    Join Date
    Jan 2008
    Posts
    107
    Thanks
    36
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Question Re: [ SOLVED (kinda) ]copy structure to QByteArray

    Well ... that almost worked ... except for QByteArray ...

    Given the following struct:

    Qt Code:
    1. //! \brief SERIAL PACKET FORMAT (Physical Layer - RS232)
    2.  
    3. typedef struct {
    4. quint8 DLE; // ASCII DLE character (16 decimal)
    5. quint8 packet_id; // packet ID
    6. // types:
    7. // 6 - ACK
    8. // 10 - Command
    9. // 14 - Date/Time Data
    10. // 21 - NAK
    11. // 38 - Unit ID/ESN
    12. // 51 - PVT (Position, Velocity, Time) Data
    13. // 135 - Legacy Stop message
    14. // 136 - Legacy text message
    15. // 161 - Fleet Management packet
    16. quint8 size_app_payload; // number of bytes of packet data (bytes 3 to n-4)
    17. QByteArray app_payload; // 0 to 255 bytes
    18. quint8 checksum; // 2's complement of the sum of all bytes from byte 1 to byte n-4 (end of the payload)
    19. quint8 DLE_end; // same as DLE
    20. quint8 ETX; // End of text - ASCII ETX character (3 decimal)
    21.  
    22. //! \note helper functions
    23. QByteArray serialize()
    24. {
    25. QByteArray byteArray;
    26.  
    27. QDataStream stream(&byteArray, QIODevice::WriteOnly);
    28.  
    29. stream << DLE
    30. << packet_id
    31. << size_app_payload
    32. << app_payload
    33. << checksum
    34. << DLE_end
    35. << ETX;
    36. return byteArray;
    37. }
    38.  
    39. void deserialize(const QByteArray& byteArray)
    40. {
    41. QDataStream stream(byteArray);
    42.  
    43. stream >> DLE
    44. >> packet_id
    45. >> size_app_payload
    46. >> app_payload
    47. >> checksum
    48. >> DLE_end
    49. >> ETX;
    50. }
    51. } serial_packet_format;
    To copy to clipboard, switch view to plain text mode 

    and the following code:

    Qt Code:
    1. serial_packet_format *sPacket = new serial_packet_format; // send fleet management packet wrapped in a serial packet format...
    2. sPacket->DLE=16;
    3. sPacket->packet_id= FLEET_MANAGEMENT; // fleet management packet
    4. // fill rest
    5. sPacket->size_app_payload=driver_id_receipt.size();
    6. sPacket->app_payload = QByteArray::QByteArray ( driver_id_receipt );
    7. // calculate 2's complement checksum
    8. sPacket->checksum = CalculateChecksum(driver_id_receipt.data(), driver_id_receipt.size() );
    9. sPacket->DLE_end=16;
    10. sPacket->ETX=3;
    11.  
    12. QByteArray serial_packet( sPacket->serialize() );
    To copy to clipboard, switch view to plain text mode 

    what happens is that upon
    Qt Code:
    1. stream << size_app_payload
    To copy to clipboard, switch view to plain text mode 

    a DWORD containing the QByteArray size is prepended to the original QByteArray...

    In other words:

    Upon execution of the above code here's what's inside sPacket:

    SERIAL PACKET CONTENTS (size=20):
    10
    FFFFFFA1
    0A

    00
    00
    00
    0A --> the 4 bytes in bold shouldn't be here!

    08
    12
    00
    00
    00
    01
    01
    00
    00
    00
    FFFFFFE4
    10
    03

    Please advise as this is the last thing to overcome my long standing problem...

    BR,
    Pedro Doria Meunier

  13. #12
    Join Date
    Jan 2008
    Location
    Poland
    Posts
    687
    Thanks
    4
    Thanked 140 Times in 132 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: [ SOLVED (kinda) ]copy structure to QByteArray

    QDataStream is a class for serializing objects. But it can append its own info about serializing object. So don't expect it would be byte to byte what you want. It is made in such way that when you write something to QDataStream (with operator <<) and then you can read it from it on the other end (with operator >>) then you get the same. But who cares what is in the middle :] A little example : let's say you have a QString str("Hello"); then you write it to QDataStream object. In this stream the QDataStream can do whateveer it wants it can even append " World!" to your string :] but when you read string fron QDataStream it returns what you wrote: QString("Hello"). So if you want to have a QByteArray containing only your own data then put every byte of your data separately. For example, if you have an 32-bit integer you can do:
    Qt Code:
    1. int num = 158;
    2. for (int i = 0; i < 4; ++i) {
    3. ba += quint8((num >> i*8) & 0x000000ff);
    4. }
    To copy to clipboard, switch view to plain text mode 
    and now you have every byte of your int written to byte array. Then you have to construct one int from 4 bytes from byte array on the other side.
    I would like to be a "Guru"

    Useful hints (try them before asking):
    1. Use Qt Assistant
    2. Search the forum

    If you haven't found solution yet then create new topic with smart question.

  14. #13
    Join Date
    Jan 2008
    Posts
    107
    Thanks
    36
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: [ SOLVED (kinda) ]copy structure to QByteArray

    Regarding the last post...
    (involving qdatastream << qbytearray )

    From Qt Assistant, "Format of the QDataStream Operators"

    QByteArray
    If the byte array is null: 0xFFFFFFFF (quint32)
    Otherwise: the array size (quint32) followed by the array bytes, i.e. size bytes


    So, from what I see, QDataStream doesn't do whatever "comes to its mind".
    It's simply doing what it's told...

    What I need to do is simply eliminate the use of QByteArray from the structure or find a fast, elegant, way to chop those array size bytes ...

    BR,
    Pedro Doria Meunier

  15. #14
    Join Date
    Oct 2009
    Posts
    8
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: [ SOLVED (kinda) ]copy structure to QByteArray

    Ok. By the looks of things you're sending this data to hardware for processing. I didn't realise that.

    In this case you could use a struct as you were planning to. It's quite common practice. You will probably have to tell the compiler not to pad out the struct, but I see in another thread you are already aware of that. If you are only targeting a single platform/compiler and don't have endianness worries, then you could do it this way. All you need to do is reinterpret_cast the struct into an unsigned char* (or whatever type your send function takes). eg:

    Qt Code:
    1. #pragma pack(push, 1)
    2. struct MyStruct
    3. {
    4. unsigned char c;
    5. unsigned int i;
    6. };
    7. #pragma pack(pop)
    8.  
    9. void send(unsigned char* buf, size_t length)
    10. {
    11. // send buf
    12. }
    13.  
    14. int main()
    15. {
    16. MyStruct myObj;
    17. myObj.c = 'A';
    18. myObj.i = 1;
    19.  
    20. send(reinterpret_cast<unsigned char*>(&myObj), sizeof(myObj));
    21.  
    22. return 0;
    23. }
    To copy to clipboard, switch view to plain text mode 

    My personal preference is to write portable code. So I would only do it this way if performance absolutely demanded it. Instead I would probably detect the endianness of the host at runtime, construct an unsigned char array of the correct size, reinterpret_cast the array at the appropriate offsets to copy in the appropriate values - applying endian conversions if necessary. But to each their own.

    Edit: I notice Qt provides qFromBigEndian to handle all the endian conversion stuff.
    Last edited by jord; 16th October 2009 at 14:27.

  16. The following user says thank you to jord for this useful post:

    pdoria (16th October 2009)

  17. #15
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,363
    Thanks
    3
    Thanked 5,012 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: [ SOLVED (kinda) ]copy structure to QByteArray

    What's the reason for using QByteArray here? Can't you just send a pointer to the structure or something (you might also want to make the structure packed to make up for compiler data alignment mechanisms)?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. Replies: 1
    Last Post: 27th November 2014, 09:11
  2. How to copy sellected ellipse area from image
    By adamsakli in forum Newbie
    Replies: 2
    Last Post: 24th September 2009, 22:11
  3. How to copy selected ellipse area from image
    By adamsakli in forum Qt Programming
    Replies: 5
    Last Post: 24th September 2009, 19:54
  4. QByteArray problem
    By Misenko in forum Qt Programming
    Replies: 17
    Last Post: 4th October 2008, 21:53
  5. Replies: 1
    Last Post: 1st March 2006, 11:43

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.