Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. Converting QString to char * fails....
Forum Updated to NodeBB v4.3 + New Features

Converting QString to char * fails....

Scheduled Pinned Locked Moved Unsolved C++ Gurus
16 Posts 5 Posters 2.9k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Anonymous_Banned275

    I need to convert QString to char * and getting this error .

    What am I doing wrong ?

    Many thanks for any help.

     char * command = text.toStdString().c_str();
    
          text = ProcessCommand_Raw(command, text);
          qDebug() << text;
    

    /mnt/RAID_124/PROJECTS_MAR15_REG_EXP/CCC_SOURCE/Bluetoothctl/mainwindow_bluetoothctl.cpp:316: error: cannot initialize a variable of type 'char *' with an rvalue of type 'const char *'
    mainwindow_bluetoothctl.cpp:316:14: error: cannot initialize a variable of type 'char *' with an rvalue of type 'const char *'
    char * command = text.toStdString().c_str();
    ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~

    Christian EhrlicherC Online
    Christian EhrlicherC Online
    Christian Ehrlicher
    Lifetime Qt Champion
    wrote on last edited by Christian Ehrlicher
    #2

    @AnneRanch said in Converting QString to char * fails....:

    What am I doing wrong ?

    You're working on a temporary object returned by text.toStdString()

    See also https://forum.qt.io/topic/124936/convert-qstring-pointer-to-char-pointer/9

    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
    Visit the Qt Academy at https://academy.qt.io/catalog

    1 Reply Last reply
    2
    • Kent-DorfmanK Offline
      Kent-DorfmanK Offline
      Kent-Dorfman
      wrote on last edited by
      #3

      Actually the problem is that OP is trying to implicitly cast away const.

      using the temporary pointer value should be OK as long as the owning object exists and isn't modified. thus the reason the returned value needs to be const. It's a protection to keep you from trying to modify the memory it points to.

      I light my way forward with the fires of all the bridges I've burned behind me.

      Christian EhrlicherC 1 Reply Last reply
      0
      • Kent-DorfmanK Kent-Dorfman

        Actually the problem is that OP is trying to implicitly cast away const.

        using the temporary pointer value should be OK as long as the owning object exists and isn't modified. thus the reason the returned value needs to be const. It's a protection to keep you from trying to modify the memory it points to.

        Christian EhrlicherC Online
        Christian EhrlicherC Online
        Christian Ehrlicher
        Lifetime Qt Champion
        wrote on last edited by
        #4

        @Kent-Dorfman It will compile when it's const but will crash afterwards or eat kittens...

        Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
        Visit the Qt Academy at https://academy.qt.io/catalog

        1 Reply Last reply
        2
        • Kent-DorfmanK Offline
          Kent-DorfmanK Offline
          Kent-Dorfman
          wrote on last edited by
          #5
          void StrTest() {
              QString testQStr("Hello World!");
              const char* ptr = testQStr.toStdString().c_str();
              std::cout << "[";
              while (*ptr != '\0') {
                  std::cout << *(ptr++);
              }
              std::cout << "]" << std::endl;
          }
          
          

          Respectfully,
          This works fine, unless you modify or destroy testQStr. Only way this should break is if testQStr object is implicitly modified behind the scenes before its destructor is executed, and you then try to use ptr without again resetting ptr by calling toStdString.c_str().

          If I do testQStr.clear() then reference its data thru ptr then all bets are off though.

          The larger argument is whether it is a good idea to access the QString data via raw pointer then pass that pointer to a subfunction...It is not, as it would be better to pass QString by reference to Process_Raw_Command, for the sake of code safety, thus negating the need to return "text" from that function in the first place.

          I light my way forward with the fires of all the bridges I've burned behind me.

          Chris KawaC JonBJ 2 Replies Last reply
          0
          • Kent-DorfmanK Kent-Dorfman
            void StrTest() {
                QString testQStr("Hello World!");
                const char* ptr = testQStr.toStdString().c_str();
                std::cout << "[";
                while (*ptr != '\0') {
                    std::cout << *(ptr++);
                }
                std::cout << "]" << std::endl;
            }
            
            

            Respectfully,
            This works fine, unless you modify or destroy testQStr. Only way this should break is if testQStr object is implicitly modified behind the scenes before its destructor is executed, and you then try to use ptr without again resetting ptr by calling toStdString.c_str().

            If I do testQStr.clear() then reference its data thru ptr then all bets are off though.

            The larger argument is whether it is a good idea to access the QString data via raw pointer then pass that pointer to a subfunction...It is not, as it would be better to pass QString by reference to Process_Raw_Command, for the sake of code safety, thus negating the need to return "text" from that function in the first place.

            Chris KawaC Offline
            Chris KawaC Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on last edited by Chris Kawa
            #6

            @Kent-Dorfman said:

            This works fine, unless you modify or destroy testQStr

            This is not fine. It's undefined behavior. This is not a question of if testQStr exists or not or is modified or not. toStdString() creates a temporary unnamed object and copies the data from testQStr. Remember that QString holds UTF-16 data and toStdString() creates a copy of that data converted to UTF-8, so the final c_str() does not return pointer to the original data but to the temporary copy. The temporary std::string is destroyed at ;, so the resulting ptr points to released memory of that temporary.

            So again - ptr does not point to data of testQStr. It points to data of the temporary std::string, which is not the same. Accessing it past ; is accessing released memory. Always, no matter if it's const or not.

            JonBJ 1 Reply Last reply
            2
            • Chris KawaC Chris Kawa

              @Kent-Dorfman said:

              This works fine, unless you modify or destroy testQStr

              This is not fine. It's undefined behavior. This is not a question of if testQStr exists or not or is modified or not. toStdString() creates a temporary unnamed object and copies the data from testQStr. Remember that QString holds UTF-16 data and toStdString() creates a copy of that data converted to UTF-8, so the final c_str() does not return pointer to the original data but to the temporary copy. The temporary std::string is destroyed at ;, so the resulting ptr points to released memory of that temporary.

              So again - ptr does not point to data of testQStr. It points to data of the temporary std::string, which is not the same. Accessing it past ; is accessing released memory. Always, no matter if it's const or not.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #7

              @Chris-Kawa said in Converting QString to char * fails....:

              So again - ptr does not point to data of testQStr. It points to data of the temporary std::string, which is not the same. Accessing it past ; is accessing released memory. Always, no matter if it's const or not.

              +1. This is what I wanted to say. I don't see what @Kent-Dorfman's comment about const has to do with it. It's not just to do with not writing to the data, where const would be relevant, it's that the address returned points to an area of memory which is "no longer valid" after the expression/statement in which toStdString() is used concludes.

              You can copy the data from the pointer to your own storage or you can pass it as a parameter from the line where it's called, but that's all. OOI, I presume the address it returns/the temporary area is actually on the stack, right? So if it survives after the statement that's just because nothing else has yet re-used that stack area, but it will happen soon.

              Chris KawaC 1 Reply Last reply
              0
              • JonBJ JonB

                @Chris-Kawa said in Converting QString to char * fails....:

                So again - ptr does not point to data of testQStr. It points to data of the temporary std::string, which is not the same. Accessing it past ; is accessing released memory. Always, no matter if it's const or not.

                +1. This is what I wanted to say. I don't see what @Kent-Dorfman's comment about const has to do with it. It's not just to do with not writing to the data, where const would be relevant, it's that the address returned points to an area of memory which is "no longer valid" after the expression/statement in which toStdString() is used concludes.

                You can copy the data from the pointer to your own storage or you can pass it as a parameter from the line where it's called, but that's all. OOI, I presume the address it returns/the temporary area is actually on the stack, right? So if it survives after the statement that's just because nothing else has yet re-used that stack area, but it will happen soon.

                Chris KawaC Offline
                Chris KawaC Offline
                Chris Kawa
                Lifetime Qt Champion
                wrote on last edited by
                #8

                It's all in the thread linked by Christian.
                Basically that's ok:

                someFunction(text.toStdString().c_str());
                

                and that's ok:

                const std::string text = text.toStdString();
                someFunction(text.c_str());
                

                but this is not ok:

                const char* text = text.toStdString().c_str();
                someFunction(text); //undefined behavior reading released memory
                
                1 Reply Last reply
                0
                • Kent-DorfmanK Kent-Dorfman
                  void StrTest() {
                      QString testQStr("Hello World!");
                      const char* ptr = testQStr.toStdString().c_str();
                      std::cout << "[";
                      while (*ptr != '\0') {
                          std::cout << *(ptr++);
                      }
                      std::cout << "]" << std::endl;
                  }
                  
                  

                  Respectfully,
                  This works fine, unless you modify or destroy testQStr. Only way this should break is if testQStr object is implicitly modified behind the scenes before its destructor is executed, and you then try to use ptr without again resetting ptr by calling toStdString.c_str().

                  If I do testQStr.clear() then reference its data thru ptr then all bets are off though.

                  The larger argument is whether it is a good idea to access the QString data via raw pointer then pass that pointer to a subfunction...It is not, as it would be better to pass QString by reference to Process_Raw_Command, for the sake of code safety, thus negating the need to return "text" from that function in the first place.

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by JonB
                  #9

                  @Kent-Dorfman
                  I looked at how your code would behave with:

                      QString testQStr1("Hello World!");
                      const char* ptr1 = testQStr1.toStdString().c_str();
                      QString testQStr2("Goodbye Universe!");
                      const char* ptr2 = testQStr2.toStdString().c_str();
                      ...
                  

                  Screenshot from 2023-03-19 08-03-00.png

                  Notice the compiler warnings. When run I found it printed the "Hello world" from ptr1 but the output from ptr2 was empty, just the [] was printed.

                  Actually, it's funny, I tested further. Remove my two strings/variables, go back to your original code. Instead of your highly fortuitous choice of Hello World! I found that "123456789012345" outputs correctly but "1234567890123456" prints as empty! The first string is 16 bytes long (including the \0 terminator) while the second one is 17. Ubuntu 22.04, gcc 11.3.0. So something like it "works" up to 16 bytes for the temporary but fails beyond that... :)

                  Christian EhrlicherC Chris KawaC 2 Replies Last reply
                  0
                  • JonBJ JonB

                    @Kent-Dorfman
                    I looked at how your code would behave with:

                        QString testQStr1("Hello World!");
                        const char* ptr1 = testQStr1.toStdString().c_str();
                        QString testQStr2("Goodbye Universe!");
                        const char* ptr2 = testQStr2.toStdString().c_str();
                        ...
                    

                    Screenshot from 2023-03-19 08-03-00.png

                    Notice the compiler warnings. When run I found it printed the "Hello world" from ptr1 but the output from ptr2 was empty, just the [] was printed.

                    Actually, it's funny, I tested further. Remove my two strings/variables, go back to your original code. Instead of your highly fortuitous choice of Hello World! I found that "123456789012345" outputs correctly but "1234567890123456" prints as empty! The first string is 16 bytes long (including the \0 terminator) while the second one is 17. Ubuntu 22.04, gcc 11.3.0. So something like it "works" up to 16 bytes for the temporary but fails beyond that... :)

                    Christian EhrlicherC Online
                    Christian EhrlicherC Online
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote on last edited by
                    #10

                    @JonB said in Converting QString to char * fails....:

                    So something like it "works" up to 16 bytes for the temporary but fails beyond that... :)

                    No, it compiles on the compiler options, your current memory layout, the os and the moon phase - it's undefined

                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                    Visit the Qt Academy at https://academy.qt.io/catalog

                    JonBJ 1 Reply Last reply
                    1
                    • Christian EhrlicherC Christian Ehrlicher

                      @JonB said in Converting QString to char * fails....:

                      So something like it "works" up to 16 bytes for the temporary but fails beyond that... :)

                      No, it compiles on the compiler options, your current memory layout, the os and the moon phase - it's undefined

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by JonB
                      #11

                      @Christian-Ehrlicher
                      I am aware of this, as I wrote earlier! I am just trying to illustrate why maybe it worked for @Kent-Dorfman on his original string but demonstrate a simple case where it does not.... I find it "interesting" what something happens around 16 bytes in practice under my OS/gcc, even if you do not :)

                      1 Reply Last reply
                      1
                      • JonBJ JonB

                        @Kent-Dorfman
                        I looked at how your code would behave with:

                            QString testQStr1("Hello World!");
                            const char* ptr1 = testQStr1.toStdString().c_str();
                            QString testQStr2("Goodbye Universe!");
                            const char* ptr2 = testQStr2.toStdString().c_str();
                            ...
                        

                        Screenshot from 2023-03-19 08-03-00.png

                        Notice the compiler warnings. When run I found it printed the "Hello world" from ptr1 but the output from ptr2 was empty, just the [] was printed.

                        Actually, it's funny, I tested further. Remove my two strings/variables, go back to your original code. Instead of your highly fortuitous choice of Hello World! I found that "123456789012345" outputs correctly but "1234567890123456" prints as empty! The first string is 16 bytes long (including the \0 terminator) while the second one is 17. Ubuntu 22.04, gcc 11.3.0. So something like it "works" up to 16 bytes for the temporary but fails beyond that... :)

                        Chris KawaC Offline
                        Chris KawaC Offline
                        Chris Kawa
                        Lifetime Qt Champion
                        wrote on last edited by Chris Kawa
                        #12

                        The language spec says it's undefined and that's it.

                        Consider this as one of gazillion possible scenarios - applications allocate memory in pages and let's say it just so happens that this temporary string is allocated somewhere in the middle of a page used by other things too. The string is deleted, memory is freed, but the page stays resident, because it's still used by that other stuff. Nothing else happens to write there for a while. Cool, seems like you can still read the string and it "works". The OS is not even giving you hard time about it because it's your page after all. But next time your string happens to be allocated at the beginning of a, otherwise empty, page and when the string is deleted the page becomes empty again and gets unmapped. The memory manager gives it to something else, say Mario64 is running in the background and takes that page. Now you have an access violation on the OS level, because you're trying to read an address out of mapped memory space, so hard crash. That's undefined behavior for you. You can probe it however you like and think you have a pattern, but you don't, you just stumbled upon a locally stable transient state, with plethora of variables in the system attached, that can change it.

                        As for the "works up to 16 bytes" - that's most probably the size of SSO buffer (small string optimization). The strings up to that size use internal buffer, and larger go to the heap.

                        JonBJ 1 Reply Last reply
                        0
                        • Chris KawaC Chris Kawa

                          The language spec says it's undefined and that's it.

                          Consider this as one of gazillion possible scenarios - applications allocate memory in pages and let's say it just so happens that this temporary string is allocated somewhere in the middle of a page used by other things too. The string is deleted, memory is freed, but the page stays resident, because it's still used by that other stuff. Nothing else happens to write there for a while. Cool, seems like you can still read the string and it "works". The OS is not even giving you hard time about it because it's your page after all. But next time your string happens to be allocated at the beginning of a, otherwise empty, page and when the string is deleted the page becomes empty again and gets unmapped. The memory manager gives it to something else, say Mario64 is running in the background and takes that page. Now you have an access violation on the OS level, because you're trying to read an address out of mapped memory space, so hard crash. That's undefined behavior for you. You can probe it however you like and think you have a pattern, but you don't, you just stumbled upon a locally stable transient state, with plethora of variables in the system attached, that can change it.

                          As for the "works up to 16 bytes" - that's most probably the size of SSO buffer (small string optimization). The strings up to that size use internal buffer, and larger go to the heap.

                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by JonB
                          #13

                          @Chris-Kawa said in Converting QString to char * fails....:

                          @JonB No experiments you make, even if they are reproducible on your machine, are meaningful. The language spec says it's undefined and that's it.

                          Why is everyone blasting me?? I am just playing to find a case to illustrate to @Kent-Dorfman which he might try and might show him how it could go wrong even though his test did work Ok for him. Does everyone what to shoot me?!

                          As for the "works up to 16 bytes" - that's most probably the size of SSO buffer (small string optimization). The strings up to that size use internal buffer, and larger go to the heap.

                          Exactly this! :)

                          Chris KawaC 1 Reply Last reply
                          0
                          • JonBJ JonB

                            @Chris-Kawa said in Converting QString to char * fails....:

                            @JonB No experiments you make, even if they are reproducible on your machine, are meaningful. The language spec says it's undefined and that's it.

                            Why is everyone blasting me?? I am just playing to find a case to illustrate to @Kent-Dorfman which he might try and might show him how it could go wrong even though his test did work Ok for him. Does everyone what to shoot me?!

                            As for the "works up to 16 bytes" - that's most probably the size of SSO buffer (small string optimization). The strings up to that size use internal buffer, and larger go to the heap.

                            Exactly this! :)

                            Chris KawaC Offline
                            Chris KawaC Offline
                            Chris Kawa
                            Lifetime Qt Champion
                            wrote on last edited by
                            #14

                            @JonB Come on. You know you like it this way :)
                            Sorry, I wasn't trying to blast you. Just gave another example. We're on the same page here I think (not in address space sense :P ).

                            1 Reply Last reply
                            0
                            • Kent-DorfmanK Offline
                              Kent-DorfmanK Offline
                              Kent-Dorfman
                              wrote on last edited by
                              #15

                              OK guys. I see your point now. My interprettation of toStdString was that it was an accessor, not a copier: iow, referencing the data directly from within QString. I was mistaken.

                              I think I'll just stick with std::string...I like it better. ;^)

                              I light my way forward with the fires of all the bridges I've burned behind me.

                              Chris KawaC 1 Reply Last reply
                              0
                              • Kent-DorfmanK Kent-Dorfman

                                OK guys. I see your point now. My interprettation of toStdString was that it was an accessor, not a copier: iow, referencing the data directly from within QString. I was mistaken.

                                I think I'll just stick with std::string...I like it better. ;^)

                                Chris KawaC Offline
                                Chris KawaC Offline
                                Chris Kawa
                                Lifetime Qt Champion
                                wrote on last edited by Chris Kawa
                                #16

                                @Kent-Dorfman The problem with std::string is that it's terrible for stuff like paths or any user input. You can technically store an UTF-8 string in it, but it's kinda clunky, because size() returns number of elements and iterators go over them too, but some UTF-8 characters will consist of multiple of those, up to 4, so the size() method for some UTF-8 strings would return up to 4x the actual length of the string. Searching for multibyte characters in it is also painfull.
                                For this stuff something like std::wstring could be better, as it could naturally hold most of the useful UTF16 subset, but it would still have the same issue with surrogate characters. Also wchar_t on Windows and Linux has different size so std::wstring is pretty useless, especially for serialization. In C++17 we have std::filesystem::path I guess, but strings in C++ are a bit of a mess to be honest. I like QString because it "just works" most of the time. Sure, a bit bloated due to 16bit storage, but very convenient.

                                1 Reply Last reply
                                2

                                • Login

                                • Login or register to search.
                                • First post
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • Users
                                • Groups
                                • Search
                                • Get Qt Extensions
                                • Unsolved