Results 1 to 12 of 12

Thread: Can someone explain me this phenomenon with QByteArray(struct,memcpy...)?

  1. #1
    Join Date
    Jul 2008
    Posts
    66
    Thanks
    5
    Qt products
    Qt4
    Platforms
    Windows

    Question Can someone explain me this phenomenon with QByteArray(struct,memcpy...)?

    Hi,

    I have the following struct, where I need a dynamic char array in it.
    I allocate memory for the dynamic array, fill the struct and put the whole thing into a QByteArray.
    This QByteArray will be used later to get back this struct and access the struct content.
    While converting to QByteArray and back I detected something what confused me.
    Maybe you can help me.

    Qt Code:
    1. struct test{
    2. int value_a;
    3. unsigned short value_b;
    4. char *c;
    5. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. test *ptr = new test; //creating a new instance
    2.  
    3. ptr->value_a = 5; //filling the struct instance -----begin
    4. ptr->value_b = 12;
    5.  
    6. ptr->c = new char[2 * sizeof(char)];
    7. ptr->c[0] = 'A';
    8. ptr->c[1] = 'B'; //filling ----------------------------end
    9.  
    10.  
    11.  
    12. char *p = (char*)ptr; //need to cast it to char* to make a QByteArray
    13.  
    14. QByteArray bytearray(p, 4+ 2 + 2 * sizeof(char)); // 4bytes (integer) + 2bytes (unsigned short) + 2bytes (char array with 'A' and 'B')
    15.  
    16.  
    17.  
    18. test *xy = (test*)bytearray.data(); // now getting back the data from QbyteArray
    19. int p = xy->a;
    20. unsigned short q = xy->b;
    21.  
    22. char r[2];
    23. memcpy(&r,xy->c,2); // copy the original array with 'A' and 'B' to r[2]
    To copy to clipboard, switch view to plain text mode 

    When I try to access here xy->c (the array), I get an invalid pointer.
    Can't access it, so memcpy fails.

    So now the confusing thing:
    When I increase the dynamic array size to 3 like this:

    Qt Code:
    1. ptr->c = new char[3 * sizeof(char)];
    2. ptr->c[0] = 'A';
    3. ptr->c[1] = 'B';
    4. ptr->c[2] = 'C';
    To copy to clipboard, switch view to plain text mode 

    And also change other places from "2 * sizeof(char)" to "3 * sizeof(char)"


    It WORKS!!!
    But why not with an array of 2 bytes?


  2. #2
    Join Date
    Jul 2008
    Posts
    66
    Thanks
    5
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Can someone explain me this phenomenon with QByteArray(struct,memcpy...)?

    I think i solved it...

    Qbytearray copied just my pointer not the content.

    I thought that it makes a deep copy???

    How can I do the above thing correct?

  3. #3
    Join Date
    Oct 2006
    Location
    New Delhi, India
    Posts
    2,467
    Thanks
    8
    Thanked 334 Times in 317 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Can someone explain me this phenomenon with QByteArray(struct,memcpy...)?

    May be QByteArray::fromRawData might be of some help to u

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

    Default Re: Can someone explain me this phenomenon with QByteArray(struct,memcpy...)?

    a) how could it make a deep copy? it can hardly know what structure hides behind that char*?
    b) even with the bitwise copy: as the pointer is copied (and thus stil points at the same spot in memory) the string behind (your xy->c) should be accessible. What error do you get?
    c) because of alignment issues you should NOT calculate sizes like that: just use sizeof(test)
    d) Is there a specific reason for not using a std::string or some real container instead of that raw pointer? (A good reason would be: I have to interface that to C.)

    HTH

  5. #5
    Join Date
    Jul 2008
    Posts
    66
    Thanks
    5
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Can someone explain me this phenomenon with QByteArray(struct,memcpy...)?

    Hi,

    a)
    I give it the whole size of bytes to be copied from the source. So I thought it could make a "blind-copy".

    OR

    Behind char* is just an array of chars. I could put a "\0" at the end so it could know where to end the bit-wise copy of the content.

    b) The content is accessable when I give QByteArray (Ctor) the correct size to be copied.
    (+4byte for the char *)
    Before I knew that it copied just the pointer I gave it 2 bytes, because the content of the array was just 'A' and 'B' => 2Bytes.

    c)
    alignment issues: If you mean what I mean:
    I solved it with "pragma pack". So , this is not a problem.
    The whole structure's size is known..there could not be a an extra-bit filled up by the compiler.

    d)
    The whole structure content must be send over serial port.
    I need to use simple structure elements because the other side of the network just knows basic data-types.
    int,char,ushort,,...

    The QByteArray outside is not a MUST. I use it for internal stuff.

    Is there another of doing this?

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

    Default Re: Can someone explain me this phenomenon with QByteArray(struct,memcpy...)?

    What I meant was: if you cast the test* to a char*, QByteArray can not know that this char* actually is a test* and contains a member c that you would like to have deep-copied...

    Anyway:
    Neither a std::string nor a char* can be sent "as is" over network. For both what you want is to send the actual string data. The receiver won't be happy with a pointer value from your machine (or process even).

    You have to choices here:
    1) use a fixed size buffer in test (i.e. something like char c[100]); that might be ok if you can guarantee the string to never exceed that
    2) define a protocol for sending an arbitratry string. you might say: from here on is my string and it ends on the first 0 byte. another common approach is to first send the length and then the data.

    For sending over a QIODeviceyou can either use a QByteArrayor just use QIODevice::write() with the char* interface. No real difference. The real issue about sending a string won't go away whatever you choose.

    HTH

    PS: Even if you use (compiler/platform dependent stuff like) #pragma, the code will break if you add further members to test. Therefore it is a good idea to use sizeof(test) anyway.

  7. The following user says thank you to caduel for this useful post:

    donglebob (30th December 2008)

  8. #7
    Join Date
    Jul 2008
    Posts
    66
    Thanks
    5
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Can someone explain me this phenomenon with QByteArray(struct,memcpy...)?

    Anyway:
    Neither a std::string nor a char* can be sent "as is" over network. For both what you want is to send the actual string data. The receiver won't be happy with a pointer value from your machine (or process even).
    Right
    Thats what I wanted to do...but the mistake was that it copied the ptr .

    1) use a fixed size buffer in test (i.e. something like char c[100]); that might be ok if you can guarantee the string to never exceed that
    I know, this would be the easiest way. I wanted to make it a little bit flexible.
    The user could enter 50 bytes or 150 bytes. That was the reason why I wanted to make a dynamic char array.

    2) define a protocol for sending an arbitratry string. you might say: from here on is my string and it ends on the first 0 byte. another common approach is to first send the length and then the data.
    I have already defined a protocol.
    These structs are known on both sides.
    The struct includes at the beginning the whole struct size in bytes. So its not a problem to find the beginning and the end of the data.
    The main problem is to use flexible-sized data (dynamic char-array).

    For sending over a QIODeviceyou can either use a QByteArrayor just use QIODevice::write() with the char* interface. No real difference. The real issue about sending a string won't go away whatever you choose
    I use the WinAPI function WriteFile to send the byte-array out of the interface.

  9. #8
    Join Date
    Jul 2008
    Posts
    66
    Thanks
    5
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Can someone explain me this phenomenon with QByteArray(struct,memcpy...)?

    Thanks for your help.
    I decided to build an own semi-automatic "QByteBuilder-Function", which goes through the dynamic array and copies the values...

  10. #9
    Join Date
    Aug 2010
    Posts
    2
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Can someone explain me this phenomenon with QByteArray(struct,memcpy...)?

    (1) sizeof(test) would be 12 bytes
    = (sizeof(int) + sizeof(unsigned short) + sizeof(_padding_) + sizeof(char *));
    Please note that the size of struct test would not change even if you change allocation size (array size) of
    prt->c.
    Deep copy means that ((uchar *)ptr != (uchar *)xy).
    However, ((uchar *)ptr->c == (uchar *)xy->c), i.e. ptr->c would not be copied.

    Qt Code:
    1. struct test{
    2. int value_a;
    3. unsigned short value_b;
    4. /* char _padding_[2]; */ //automatically added by compiler
    5. char *c;
    6. };
    To copy to clipboard, switch view to plain text mode 

    (2) The code below works:

    Qt Code:
    1. test *ptr = new test; //creating a new instance
    2.  
    3. ptr->value_a = 5; //filling the struct instance -----begin
    4. ptr->value_b = 12;
    5.  
    6. ptr->c = new char[2 * sizeof(char)];
    7. ptr->c[0] = 'A';
    8. ptr->c[1] = 'B'; //filling ----------------------------end
    9.  
    10. char *p = (char*)ptr; //need to cast it to char* to make a QByteArray
    11.  
    12. qDebug() << "[sizeof(test)]" << sizeof(test);
    13. QByteArray bytearray(p, sizeof(test)); // 12 bytes
    14.  
    15. test *xy = (test*)bytearray.data(); // now getting back the data from QbyteArray
    16. int A = xy->value_a;
    17. qDebug() << "[A]" << A;
    18. unsigned short B = xy->value_b;
    19. qDebug() << "[B]" << B;
    20.  
    21. char C[2];
    22. memcpy(&C,xy->c,2); // copy the original array with 'A' and 'B' to r[2]
    23.  
    24. qDebug() << C[0] << C[1];
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. "ptr=0x09be88a8"
    2. "ptr->c=0x09bd3638"
    3. [sizeof(test)] 12
    4. "xy=0x09bd3450"
    5. "xy->c=0x09bd3638"
    6. [A] 5
    7. [B] 12
    8. [C] A B
    To copy to clipboard, switch view to plain text mode 

  11. #10
    Join Date
    Aug 2010
    Posts
    2
    Qt products
    Qt4
    Platforms
    Windows

    Default COW (copy-on-write)

    Qt Code:
    1. #include <QtCore>
    2.  
    3. struct test{
    4. int value_a;
    5. unsigned short value_b;
    6. };
    7.  
    8. int main(int argc, char *argv[])
    9. {
    10. QCoreApplication a(argc, argv);
    11. test TA;
    12. TA.value_a = 5;
    13. TA.value_b = 12;
    14. TA.c = "AB";
    15. test TB = TA;
    16. qDebug() << QString("(1)TA.c.constData()=0x%1").arg((uint)TA.c.constData(), 8, 16, QChar('0'));
    17. qDebug() << QString("(2)TB.c.constData()=0x%1").arg((uint)TB.c.constData(), 8, 16, QChar('0'));
    18. TB.c = "CD";
    19. qDebug() << QString("(3)TA.c.constData()=0x%1").arg((uint)TA.c.constData(), 8, 16, QChar('0'));
    20. qDebug() << QString("(4)TB.c.constData()=0x%1").arg((uint)TB.c.constData(), 8, 16, QChar('0'));
    21. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. "(1)TA.c.constData()=0x003d5308"
    2. "(2)TB.c.constData()=0x003d5308"
    3. "(3)TA.c.constData()=0x003d5308"
    4. "(4)TB.c.constData()=0x003d5338"
    To copy to clipboard, switch view to plain text mode 

    Qt uses copy-on-write. When you copy QByteArray located in some sturuct, QByteArray::constData() points to the same address (seemingly shallow copy).

    However, when you modify (=write to) the (seemingly shallow-copied) QByteArray, it is then copied (detached) from the original one.

    COW classes are efficient because copying them involves (basically) copying of internal data pointer (with reference counting); nevertheless from the programmers' point of view, copied data can be modified without affecting the original copy. COW automatically take care of `detaching' (copying internal data when needed), so that you can think of this `seemingly shallow copy' as `efficient deep copy'.

    COW is used widely in Qt; so that you can pass QString, QByteArray, QImage, etc. efficiently like below:
    Qt Code:
    1. QString a=b;
    2. QImage a=b;
    To copy to clipboard, switch view to plain text mode 
    As long as you don't modify, internal data (structure) is shared intelligentlly.
    The example below would be ok, because this involves passing shared (reference counting) pointer of internal (bitmap) data from the function to caller.
    Qt Code:
    1. QImage createImage()
    2. {
    3. QImage result;
    4. ....
    5. return result;
    6. }
    To copy to clipboard, switch view to plain text mode 

  12. #11
    Join Date
    Apr 2011
    Posts
    1
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Variaable size struct

    Try this.

    struct test{
    int value_a;
    unsigned short value_b;
    char c[1]; // not this is not pointer any more. it is just a place holder now
    };

    int size = sizeof (struct test) + 2 * sizeof(char);


    struct test *ptr = (struct test *)new char[size];

    QByteArray bytearry(ptr, size);
    ....

    Good Luck.
    Tom T
    Last edited by thtran; 3rd April 2012 at 04:34. Reason: updated contents

  13. #12
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: Variaable size struct

    So, you joined the forum, resurrected a three year-old thread that had been thoroughly beaten to death the first and second time, and made your first post adding only marginal information. Was there some reason?

Similar Threads

  1. please explain QUrl::isValid() to me
    By momesana in forum Qt Programming
    Replies: 5
    Last Post: 19th May 2010, 01:19
  2. could somebody please explain const to me?
    By mikro in forum General Programming
    Replies: 4
    Last Post: 29th September 2006, 14:34

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.