Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

qDebug output the message from point to QString::toLocal8Bit().data();



  • I get something wrong when i use qDebug to output message base point to QString::toLocal8Bit().data(); the source code is like this:
    QString str = "X";

    void *ptr1 = (void*)str.toLocal8Bit().data();
    void *ptr2 = (void*)str.toLocal8Bit().data();
    void *ptr3 = (void*)str.toLocal8Bit().data();
    void *ptr4 = (void*)str.toLocal8Bit().data();
    
    qDebug()<<ptr1<<*(unsigned char*)ptr1;
    qDebug()<<ptr2<<*(unsigned char*)ptr2;
    qDebug()<<ptr3<<*(unsigned char*)ptr3;
    qDebug()<<ptr4<<*(unsigned char*)ptr4;
    

    and then i got the result:
    0x10862c8 88
    0x10862c8 80
    0x10862c8 80
    0x10862c8 80
    would you encountered the result like this? please tell me how to deal with it,thanks a lot!



  • @welsey
    What is wrong? qDebug() is showing the data() as bytes (not chars), 88 looks about right for the letter X....

    If you mean why does it show different values (assuming your output is indeed accurate), that must be to do with toLocal8Bit().data() returning a temporary copy, and that being altered after you have last referenced it, maybe? E.g. try reversing the order of your output lines so it goes in order from ptr4 to ptr1, does it then get ptr4 right and the others wrong?



  • @jonb thanks for your reply, the first is quite right, but the last three is wrong, i cannot understand it.


  • Lifetime Qt Champion

    Hi,

    void *ptr1 = (void*)str.toLocal8Bit().data(); this line and the other similar are likely giving you a warning.

    From a lifetime point of view the QByteArray returned by toLocal8Bit ends at the the semicolon. The fact that the memory address you get is the same for all these calls is just luck and as you have seen, the content of that memory segment may have changed because the object that used to use it has already been destroyed and thus it may have been reused for something else.

    If you want to play with the data contained in that QByteArray you have to do it like this:

    QByteArray local8BitRepresentation = str.toLocal8Bit();
    void *ptr1 = (void*)local8BitRepresentation.data();
    void *ptr2 = (void*)local8BitRepresentation.data();
    // etc.
    


  • @welsey
    I had already appended to my reply about this. Read that. I believe we must be talking about temporary areas here, think about where these toLocal8Bit() results are getting stored/released?

    I see @SGaist is confirming this, and suggesting you need to put it into a named QByteArray so that you can play with it without it getting disposed in the middle of what you're doing.



  • @sgaist
    I'd like to press you on this, as it's quite interesting (to me at least!). Remember I am not a Qt C++-er, so I cannot test for myself.

    Looking at the code. What is it that can actually change after line 1 and before line 2:

    qDebug()<<ptr1<<*(unsigned char*)ptr1;
    qDebug()<<ptr2<<*(unsigned char*)ptr2;
    

    ? Qt does not do resource releasing in a separate thread. So I see only two possibilities as to how the second line can see different content from the first one:

    • There is an actual instruction in the machine code after line 1 which causes release. But I don't see that there will be?

    • It is the fact that the user called a Qt function like qDebug(), which itself uses Qt stuff which causes the context to be released/changed? It must be this?? So if OP had instead written:

    unsigned char c1 = *(unsigned char*)ptr1; 
    unsigned char c2 = *(unsigned char*)ptr2; 
    qDebug()<<ptr1<<c1;
    qDebug()<<ptr2<<c2;
    

    then the results would be the same?



  • @sgaist yeah, it's right, i think this is the answer, thanks a lot.


  • Lifetime Qt Champion

    @jonb Between these two lines you can have lots of stuff happening. Don't forget that there's a lot of things going on your machine while you execute your program.

    As for memory releasing, it's nothing Qt specific. The object is destroyed but you can have the next one re-created in the same place or a different one.



  • @JonB i tested it and it worked;



  • @sgaist

    @jonb Between these two lines you can have lots of stuff happening. Don't forget that there's a lot of things going on your machine while you execute your program.

    Sorry, I don't get this at all. (It may be that this is a discussion for another topic...) So far as I am aware, there is nothing which can/will change the memory area inside a process from "other things going on on machine" in the middle of normal instructions inside one's code. Unless there is another thread operating here (which I don't think there is), nothing will happen to its memory space which cannot be seen from direct instructions inside the code where we are, and I don't see anything which could do that. The fact that I believe the OP is posting it does not get altered if he tries my alternative code which does not call qDebug() between the two lines proves that the cause is whatever is happening inside qDebug() (within the process) which gives rise to the behaviour witnessed.


  • Lifetime Qt Champion

    @jonb

    The main problem with the code void *ptr1 = (void*)str.toLocal8Bit().data(); is, that ptr1 is not valid.

    Why is this? str.toLocal8Bit() creates a (temporary) QByteArray, which we could assign to a variable: QByteArray b = str.toLocal8Bit(); That would be a completely valid operation. Afterwards, we could even get a valid pointer to this array:

    QByteArray b = str.toLocal8Bit();
    void *ptr1 = (void*)b.data();
    

    Here ptr1 would be valid as long as b is valid (until the scope is closed).

    So, why is void *ptr1 = (void*)str.toLocal8Bit().data(); wrong?

    Because the temporary QByteArray is created and destroyed in the same line, hence the ptr1 points to invalid memory. Accessing this memory is undefined behavior. The object may still be there (and everything works) or not (and everything crashes).

    Edit: Side note for completeness: You can use something like const QByteArray &b = str.toLocal8Bit(); (holding a reference to the temporary object). In this case, the compiler knows what you are doing and extends the lifetime of the temporary QByteArray until b goes out of scope.

    But this only works for references!

    Regards



  • @aha_1980
    In the politest way. I do understand all of this. It is the answer to why the OP should not be writing the code he did. It is not the answer to what I am interested in, which is how the value at a given memory location gets changed between two consecutive statements which read it. My question is what changes it between these two lines (simply because I am interested).

    It seems to me that what the OP reports proves (to me) that it is the qDebug() on the first line which, as a (quite understandable) side-effect, is writing to the memory location. I did not spot that at first. I do not see what else it can be.


  • Lifetime Qt Champion

    @jonb said in qDebug output the message from point to QString::toLocal8Bit().data();:

    It is not the answer to what I am interested in, which is how the value at a given memory location gets changed between two consecutive statements which read it. My question is what changes it between these two lines (simply because I am interested).

    And that's what I liked to point out: we are talking about accessing invalid memory. You simply cannot do that.


Log in to reply