std::string nach char* konvertieren



  • Icematix schrieb:

    Da std::string den String intern sowieso als nullterminierte Zeichenkette speichert,

    Nicht zwangsläufig. Die Nullterminierung wird erst dann explizit angehängt, wenn c_str() aufgerufen wird.



  • was ist mit

    const_cast<char*>(foo.c_str)
    

    ??



  • @"sudo rm -rf", du solltest erst einmal erklären, warum du überhaupt einen "char *" benötigst...

    P.S. Klammern fehlen:

    const_cast<char*>(foo.c_str())
    


  • DocShoe schrieb:

    Icematix schrieb:

    *Schüttel*
    Da std::string den String intern sowieso als nullterminierte Zeichenkette speichert...

    Nö, tut std::string nicht. Du kannst sogar \0 im Puffer haben.

    Ich hab es mit VC++ 2008/1010 schon oft so gemacht.
    Und selbst wenn, lieber dem string ein \0 anhängen als ihn rumzukopieren.


  • Mod

    Icematix schrieb:

    Ich hab es mit VC++ 2008/1010 schon oft so gemacht.

    Toll. Und wenn du mal den Compiler wechselst? Oder eine neue Version vom VC++ rauskommt, die das nicht mehr macht?

    Und selbst wenn, lieber dem string ein \0 anhängen als ihn rumzukopieren.

    Aber genau das macht doch c_str()!



  • SeppJ schrieb:

    Und selbst wenn, lieber dem string ein \0 anhängen als ihn rumzukopieren.

    Aber genau das macht doch c_str()!

    dem string manuell ein \0 anzuhängen heißt, dass die Länge (length() / size()) vergrößert wird, obwohl die eigentliche Länger (strlen) nicht geändert wird. ist also keine gute alternative...



  • sudo rm -rf schrieb:

    Hallo, ich habe seit längerem nicht mehr programmiert und habe keine ahnung wie ich einen std::string in ein char* konvertiert bekomme...

    es klingt simpel, aber bitte HELFT MIR!

    folgendes beispiel:

    char* c;
    std::string str;
    str = "Blablub";
    c = (char*) str; //geht nicht
    

    std::string und char* sind vom Konzept her sehr verschieden. Das eine ist ein Typ für Zeichenketten, das andere ein Typ für Zeiger auf ein Zeichen bzw Zeichenkette. Daher würde ich auch das Wort "Konvertieren" vermeiden.

    Wo soll denn Dein Zeiger hinzeigen?
    Was willst Du mit dem Zeiger anstellen?

    Intern wird das string-Objekt die Zeichenketten irgendwie speichern. Abes es gibt meines Wissens nach (bisher) noch keine Garantie wie &str[i] == &str[0]+i für 0<=i && i<str.size() . Das heißt, Du kannst Dich nicht darauf verlassen, dass die Zeichen, die das string-Objekt für Dich speichert/verwaltet auch alle hintereinander im Speicher liegen -- von Nullterminierung mal ganz abgesehen. Natürlich liegt eine string-Implementierung nah, die die Zeichenkette immer linear im Speicher und auch nullterminiert ablegt. Aber wie gesagt, ich glaube, so eine Garantie, wie sie bei vector<> gemacht wird, gibt es bei string (noch) nicht.

    Man muss sich auch um die Gültigkeit der Zeichenkette, die durch den char* referenziert wird, Gedanken machen. std::string verwaltet die Zeichenkette automatisch. Wenn das string-Objekt stirbt, dann ist natürlich auch ein ehemaliger const char*, den Du über c_str() erhalten hast, ungültig. Wenn Du jetzt nur eine blöde C-API Funktion aufrufen willst, die den String gar nicht wirklich verändert, aber trotzdem "char*" verlangt, dann wäre das ein Fall, wo man darüber nachdenken kann const_cast zu benutzen. Wenn Du den char* benötigst, weil irgend eine andere Funktion die Zeichenkette verändern will, dann gibt es eigentlich keine andere Möglichkeit als eine eigene Kopie der Zeichenkette anzulegen; es sei denn, Dir ist das, was der C++ Standard garantiert egal und Du bist froh solange dein Programm mit Deinem Compiler auf Deinem Rechner unter Deinem Betriebssystem zu funktionieren scheint.

    Unschön/grenzwertig/gefählich, aber technisch OK:

    #include <stdio.h>
    #include <string>
    
    void bloede_C_funktion(char* dahateinerconstvergessen)
    {
      printf("%s\n",dahateinerconstvergessen);
    }
    
    int main()
    {
      string foo = "hello world!";
      bloede_C_funktion(const_cast<char*>(foo.c_str()));
    }
    

    Oder so:

    #include <string>
    #include <iostream>
    
    void andere_funktion(char* z)
    {
      char tmp = z[0]; z[0] = z[1]; z[1] = tmp;
    }
    
    int main()
    {
      string foo = "ehllo world!";
      vector<char> cv (foo.begin(),foo.end());
      assert(cv.size()>=2);
      andere_funktion(&cv[0]);
      foo.assign(cv.begin(),cv.end());
      std::cout << foo << '\n';
    }
    

    Sicher, dass ein const char* , der nur solange gültig ist bis das string-Objekt modifiziert wird oder stirbt, nicht ausreicht?

    kk



  • Icematix schrieb:

    Ich hab es mit VC++ 2008/1010 schon oft so gemacht.

    Das sollte man in seine coding styles aufnemen: Gutes Deisgn ist, wenns Icematix schon oft in VC++ 2008/2010 gemacht hat.

    Einen char* benötigt man, um die dahinter liegende Zeichenkette zu manipulieren und dafür ist die string Klasse nicht konzipiert. Ich würde das nicht als gefährlich oder schlecht, sondern schon als einfach falsch bezeichnen. Wenn man irgendeine C-API benutzt und für die Ausgabe o.ä. einen string mal kopiert ist das kein Weltuntergang. Wenn diese Aufrufe so häufig vorkommen und ihr Anteil an der eigenltichen Aktion dominiert ist die Wahl der string Klasse einfach falsch. Dann sollte man über z.B. über vector<char> nachdenken.



  • Das sollte man in seine coding styles aufnemen: Gutes Deisgn ist, wenns Icematix schon oft in VC++ 2008/2010 gemacht hat.

    Compilerspezifisches Gefrickel finde ich immer noch schöner als in Nutzcode mit new/delete rumzuhantieren sowie den Overhead des Kopierens auf sich zu nehmen.

    Außerdem verlangt praktisch jede API-Funktion (in der WinAPI zb jede), die einen char* entgegennimmt auch gleich die Größe, dh. es wird nicht von einer Nullterminierung ausgegangen.

    Unter der Haube hat die std::string Klasse übrigens erschreckende Ähnlichkeit mit std::vector<T>, ich würde nicht behaupten, dass die Stringklasse dafür nicht konzipiert ist.

    Aber ich muss ganz ehrlich zugeben: In fast jedem Fall der mir bis jetzt untergekommen ist, in dem eine Funktion einen per char* gezeigten Buffer beschreibt, ist die Nutzung der Stringklasse sowieso überflüssig und man sollte auf einen std::vector zurückgreifen ... 😉



  • Icematix schrieb:

    Das sollte man in seine coding styles aufnemen: Gutes Deisgn ist, wenns Icematix schon oft in VC++ 2008/2010 gemacht hat.

    Compilerspezifisches Gefrickel finde ich immer noch schöner als in Nutzcode mit new/delete rumzuhantieren sowie den Overhead des Kopierens auf sich zu nehmen.

    Außerdem verlangt praktisch jede API-Funktion (in der WinAPI zb jede), die einen char* entgegennimmt auch gleich die Größe, dh. es wird nicht von einer Nullterminierung ausgegangen.

    Amen. Code, play and pray.



  • Icematix schrieb:

    ...Overhead des Kopierens auf sich zu nehmen....

    Nunja - in den Zeiten, in denen die meisten Menschen mit Java-Anwendungen zufrieden sind und Maschinen auf dem Tisch stehen haben, die locker eine Marsmission koordinieren könnten, verliert dieser Ansatz aus den 70ern ein wenig an Brisanz. 😉

    Gruß,

    Simon2.



  • Was hast du denn genau vor, sudo? Es gibt andere Möglichkeiten, an die Zeichen eines strings zu kommen.



  • Nunja - in den Zeiten, in denen die meisten Menschen mit Java-Anwendungen zufrieden sind und Maschinen auf dem Tisch stehen haben, die locker eine Marsmission koordinieren könnten, verliert dieser Ansatz aus den 70ern ein wenig an Brisanz.

    Würde ich nicht sagen 😉
    Unterschätze mal die ganze Kopiererei und das allozieren von Heapspeicher nicht.

    Ich habe mir für ein Projekt ein Pendant zu std::string geschrieben, der allerdings statischen Speicher hat, nichts extra am Heap anlegt.

    Ergebnis: Höherer Speicherverbrauchen, stark reduzierte CPU-Auslastung.
    Und ganz ehrlich: 100MB mehr RAM verbrauch stören mich bei 8GB RAM deutlich weniger als die 20% mehr CPU-Auslastung, die das Nutzen von std::string gekostet hat 😉

    Na gut, war auch eine Anwendung die sehr viele Stringoperationen durchgeführt hat...



  • Hi,

    ich glaube trotzdem, dass in 90% der Fälle
    - das Kopieren kein Problem ist oder
    - man an anderen Stellen besser optimieren kann (Programmstruktur optimieren!) oder
    - eine bessere std::string-Implementierung Abhilfe schafft.

    Und in 98% der Fälle schaffen häßliche const-casts bzw. eine sehr rigide "Bloß-nicht-Kopieren"-Strategie mehr Probleme als sie lösen.... (gerade über einen kompletten Lebenszyklus einer Anwendung betrachtet).
    😉

    Gruß,

    Simon2.



  • Icematix schrieb:

    Na gut, war auch eine Anwendung die sehr viele Stringoperationen durchgeführt hat...

    Dafür ist auch nicht std::string, sondern die Streamklassen vorgesehen.



  • Ein guter Compiler wird doch sowieso erkennen, ob was kopiert werden muß.



  • Alles kann der auch nicht wegoptimieren.
    Er möchte einer Funktionen einen Zeiger auf eine nicht konstante Zeichenkette übergeben. Das geht mit der std::string Klasse nicht, daher muss er den Inhalt woanders hinkopieren. Oder er muss sich direkt gegen std::string entscheiden. Es könnte (?) evtl. eine STL Implementierung zulassen, den Inhalt von string per std::move in einen vector zu schieben. Glaub/weiß ich aber nicht.
    Wurde doch auch schon alles gesagt, in den meisten Fällen wird man vom Kopieren überhaupt nichts bemerken, wenn doch, dann mach anders.


Anmelden zum Antworten