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....

Converting QString to char * fails....

Scheduled Pinned Locked Moved Unsolved C++ Gurus
16 Posts 5 Posters 2.2k Views
  • 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 Offline
    A Offline
    Anonymous_Banned275
    wrote on last edited by
    #1

    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 1 Reply Last reply
    0
    • 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 Offline
      Christian EhrlicherC Offline
      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.

        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 Offline
          Christian EhrlicherC Offline
          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.

            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 Offline
                      Christian EhrlicherC Offline
                      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. ;^)

                                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