std::string und char*



  • Hey!

    CreateProcess() hat LPSTR als zweiten Parameter. Ich möchte mit std::string arbeiten, das geht hier aber wohl nicht?

    Dies dürfte ungültig sein, da std::string nicht terminiert:

    std::string string = "bla.exe -test 1 2 3"
    CreateProcess("bla.exe", &string[0], ...)
    

    Dem string '\0' anhängen ignoriert std::string.

    Was also tun?
    Muss ich jetzt zwingend mit char-arrays und memcpy() rumfrickeln?

    MfG



  • vielleicht

    CreateProcess("bla.exe", stri.c_str(), ...)
    


  • Geht leider nicht, da der zweite Parameter char* ist, doch c_str() gibt const char* zurück.
    Laut MSDN sollte es funktionieren, die Kommandozeile komplett im ersten Argument zu übergeben. Geht aber anscheinend nicht, es startet kein Programm:

    CreateProcess("bla.exe -test 1 2 3", 0, ...)

    MSDN schreibt auch dass die Unicode-version schreibend auf Parameter 2 zugreifen könnte:

    http://msdn.microsoft.com/en-us/library/ms682425 (lpCommandLine 2. Absatz)

    Jedoch geht dadurch für mich nicht 100%ig hervor dass ich bei der ASCII Version einen const_cast machen darf.

    😕


  • Administrator

    char cmdLine[] = "bla.exe -test 1 2 3";
    CreateProcess("bla.exe", &cmdLine[0], ...);
    
    // Aber ich nehme mal an, dass du wirklich einen std::string vorliegen hast.
    // Dann musst du es wohl so machen:
    std::string cmdLine; // Mit was auch immer gefüllt.
    
    // Puffer erstellen, auf den auch geschrieben werden kann.
    std::vector<char> buffer(cmdLine.begin(), cmdLine.end());
    
    // Nullterminierung.
    buffer.push_back(0);
    
    CreateProcess("bla.exe", &buffer[0], ...);
    

    const_cast wäre nach Dokumentation tatsächlich möglich. Da würde ich aber minimum CreateProcessA hinschreiben. Aber trotzdem rate ich davon ab. Da muss nur jemand anderes kommen, oder einem selbst in ein paar Monaten und man denkt sich nichts dabei, verändert was kleines und BUMM. 😉

    Grüssli



  • Frage15 schrieb:

    Laut MSDN sollte es funktionieren, die Kommandozeile komplett im ersten Argument zu übergeben. Geht aber anscheinend nicht, es startet kein Programm:

    CreateProcess("bla.exe -test 1 2 3", 0, ...)

    MSDN schreibt auch dass die Unicode-version schreibend auf Parameter 2 zugreifen könnte:

    hab ich auch so verstanden:

    MSDN schrieb:

    The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.

    The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.

    Allerdings solltest du es damit mal im WinAPI-Forum und nicht im C++ Forum versuchen...

    Ich seh gerade noch das Bsp ganz unten:

    MSDN schrieb:

    LPTSTR szCmdline[] = _tcsdup( TEXT("\"C:\\Program Files\\MyApp\" -L -S") );
    CreateProcess(NULL, szCmdline, /*...*/);
    

    Hast dus mal so rum probiert?
    (Sorum ists auch hier gemacht:
    http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx
    )

    bb



  • Ich entscheide mich für den const_cast<>.

    Ah danke @unskilled, so funktionierts, ich Depp hatte die Parameter auch extra in Anführungsstrichen.

    MfG



  • Frage15 schrieb:

    Ah danke @unskilled, so funktionierts, ich Depp hatte die Parameter auch extra in Anführungsstrichen.

    kaum macht mans richtig - schon funktionierst ^^
    auch, wenn sich das (die doku, also die msdn) in meinen augen ein wenig wiederspricht 😉

    bb



  • Frage15 schrieb:

    CreateProcess() hat LPSTR als zweiten Parameter. Ich möchte mit std::string arbeiten, das geht hier aber wohl nicht?

    Dies dürfte ungültig sein, da std::string nicht terminiert:

    std::string string = "bla.exe -test 1 2 3"
    CreateProcess("bla.exe", &string[0], ...)
    

    Doch, das geht so! std::string hat immer eine terminierende '\0' hinten und eine zweite brauchst du nicht.



  • Badestrand schrieb:

    Frage15 schrieb:

    CreateProcess() hat LPSTR als zweiten Parameter. Ich möchte mit std::string arbeiten, das geht hier aber wohl nicht?

    Dies dürfte ungültig sein, da std::string nicht terminiert:

    std::string string = "bla.exe -test 1 2 3"
    CreateProcess("bla.exe", &string[0], ...)
    

    Doch, das geht so! std::string hat immer eine terminierende '\0' hinten und eine zweite brauchst du nicht.

    Ne, das ist absolut undefiniert.



  • Tachyon schrieb:

    Ne, das ist absolut undefiniert.

    Selbst wenn, dieses Verhalten findest du in allen Implementationen, die du unter Windows nutzen kannst. Geht ja ohne große Frickelei auch nicht anders, da c_str() einen const char* mit '\0' hinten herausgibt, dabei den string aber nicht ändern darf (weil const).



  • Badestrand schrieb:

    Selbst wenn, dieses Verhalten findest du in allen Implementationen, die du unter Windows nutzen kannst.

    Ist das so? Ich denke nicht. Und selbst wenn, wer sagt Dir, dass <benutzte Implementierung einsetzen> das nicht beim nächsten Release ändert? Und dann wundert man sich über bizarre Fehler.
    Ich würde in solchen Fällen immer auf Draveres Vorschlag zurückgreifen. Damit ist man auf der sicheren Seite, und so kompliziert isses auch nicht.

    Badestrand schrieb:

    Geht ja ohne große Frickelei auch nicht anders, da c_str() einen const char* mit '\0' hinten herausgibt, dabei den string aber nicht ändern darf (weil const).

    Ja, das ist auch gut so. Der von c_str() zurückgegebene Buffer muss nichts mit dem im String verwalteten Buffer zu tu haben.



  • Badestrand schrieb:

    ...Geht ja ohne große Frickelei auch nicht anders, da c_str() einen const char* mit '\0' hinten herausgibt, dabei den string aber nicht ändern darf (weil const).

    😕
    Was soll daran Frickelei sein? Einfach eine Kopie und fertig.

    Gruß,

    Simon2.



  • Tachyon schrieb:

    Ist das so? Ich denke nicht.

    Zumindest VS03-08, die GCC-C++-Bib und StlPort handhaben das so, warum auch sollte für char& operator[](int pos) und c_str() ein anderer Buffer angegeben werden. Es geht eben nicht sinnvoll anders. Oder zeig mir wie, dann bin ich ruhig 🙂

    Simon2 schrieb:

    Was soll daran Frickelei sein? Einfach eine Kopie und fertig.

    return strdup(m_buf) ? Zeig mal, was du meinst.



  • Badestrand schrieb:

    ...

    Simon2 schrieb:

    Was soll daran Frickelei sein? Einfach eine Kopie und fertig.

    return strdup(m_buf) ? Zeig mal, was du meinst.

    Mal nur als Skizze:

    class string {
       char* extBuf;
       char* intBuf;
       size_t len;
    public:
       char const* c_str() { 
          if(changed) {
             extBuf = new char[len+1];
             copy(intBuf, intBuf+len, extBuf);
             extBuf[len] = '\0';
          }
          return extBuf;
       }
    };
    

    Soweit ich recht weiß, gibt der Standard keine Zusage über die "Gültigkeitsdauer" des CStrings, der sich hinter dem Rückgabewert von c_str() verbirgt.

    Natürlich kann man da noch viel mit caching, reference counting, internen Arrays,.... optimieren - hier geht es nur um eine Skizze.

    Gruß,

    Simon2.



  • Badestrand schrieb:

    return strdup(m_buf) ? Zeig mal, was du meinst.

    std::string bla("Besser kopieren als probieren!");
    std::vector<std::string::value_type> buffer(bla.begin(), bla.end());
    buffer.push_back('\0');
    crazy_nonconst_evil_operations(&buffer[0]);
    


  • Simon2 schrieb:

    Mal nur als Skizze:

    Dann mach das mal, während c_str() const ist.


Anmelden zum Antworten