Frage zu C-String



  • raw* schrieb:

    In meinem Fall kann ich keinen std::string verwenden weil Binär Daten versendet werden müssen.

    Es verhält sich genau anders herum - std::string kann problemlos mit Binärdaten umgehen, während das mit C-Strings nicht möglich ist - denn ein C-String ist per Definition beim ersten NUL zu Ende.



  • Sone schrieb:

    Du willst ihn wohl zum Masochismus treiben.

    Nö, sonst hätte ich ihm vorgeschlagen alle deine posts zu lesen.

    Athar schrieb:

    Es verhält sich genau anders herum - std::string kann problemlos mit Binärdaten umgehen, während das mit C-Strings nicht möglich ist - denn ein C-String ist per Definition beim ersten NUL zu Ende.

    Man kann eben nur nicht C-Funktionen wie strcat, strlen benutzen. Deshalb habe ich ja "Länge merken und memcpy" vorgeschlagen.



  • Athar schrieb:

    Es verhält sich genau anders herum - std::string kann problemlos mit Binärdaten umgehen, während das mit C-Strings nicht möglich ist - denn ein C-String ist per Definition beim ersten NUL zu Ende.

    Ich dachte eigentlich immer char * (bzw. vector<char>(DataSize); ) müsste man für Binärdaten verwenden.

    Also ich meine wie soll ich z.b. Binärdaten aus einer Datei in einen std::string einlesen soweit ich weiss geht das doch gar nicht oder?

    Hier http://www.cplusplus.com/reference/iostream/istream/read/ wird ja auch char* benutzt mit std::string funktioniert die read bzw. write Funktion ja nicht. (Ja, ich weiss vector ist besser nehme ich auch für solche Sachen.)


  • Mod

    raw** schrieb:

    Also ich meine wie soll ich z.b. Binärdaten aus einer Datei in einen std::string einlesen soweit ich weiss geht das doch gar nicht oder?

    Hier http://www.cplusplus.com/reference/iostream/istream/read/ wird ja auch char* benutzt mit std::string funktioniert die read bzw. write Funktion ja nicht. (Ja, ich weiss vector ist besser nehme ich auch für solche Sachen.)

    Es ist zwar in C++98 streng genommen nicht definiert, dass ein String seine Elemente hintereinander speichert, aber die Implementierung, die das nicht tut, muss erst noch erfunden werden. In C++11 ist sogar garantiert, dass alles hintereinander steht. Daher kannst du die Elemente in den String genau so reinbekommen wie in einen Vector.

    Die Frage, die ich mir stelle, ist, was der Vorteil von String gegenüber Vector sein soll, wenn es um Binärdaten geht.



  • Ok, eine letzte Frage hab ich noch:

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main()
    {
    
    string abc="\x41\x42\x00\x43";
    
    ofstream f ("file.txt",ios::binary);
    f.write(abc.c_str(),4);
    
    system("PAUSE");
    return 0;
    }
    

    Wenn ich die erstellte Datei im Hexeditor anschaue dann steht dort: 41 42 00 00
    Wenn ich aber z.b. benutze

    char *abc="\x41\x42\x00\x43";
    

    dann steht in der Datei 41 42 00 43

    Im Debugger sehe ich das der string aber die Binärdaten enthält dann scheint das Problem wohl bei c._str() zu liegen aber das mach auch std::string doch char* oder nicht?

    Deshalb denke ich jetzt das char* für Binärdaten doch besser wäre weil Binärdaten natürlich auch Nullbytes enthalten können.


  • Mod

    edit: Deine Zuweisung am Anfang ist falsch. Das weist dem String einen nullterminierten C-String zu, der hier eben nur zwei Zeichen hat. Guck dir mal die anderen Konstruktoren und Funktionen von String an und was sie genau machen.

    Aber: Mich würde immer noch interessieren, warum du String und nicht Vector für Binärdaten nimmst. String ist eigentlich eher auf "normale" Zeichenketten hin designed.



  • anschaue dann steht dort: 41 42 00 00

    Die Konvertierung zwischen char* und std::string beruecksichtigt nur 0-terminierte Strings. Wenn du mittels abc.size() die Laenge vorher pruefst, so wird sie 2 sein. D.h. der Einsatz von 4 bei write ist falsch.

    char tmp[] ="\x41\x42\x00\x43";
    string abc(tmp, tmp+sizeof(tmp)-1);
    ofstream f ("file.raw",ios::binary); 
    f.write(abc.data(),abc.size());
    


  • Ahh, ich glaub jetzt hab ichs, c_str(); dachte wohl mein string wäre schon zu ende als es das Nullbyte gesehen hat.

    Ein Nullbyte Kennzeichnet ja eigentlich auch das string ende ...

    SeppJ schrieb:

    Aber: Mich würde immer noch interessieren, warum du String und nicht Vector für Binärdaten nimmst. String ist eigentlich eher auf "normale" Zeichenketten hin designed

    Ja, Vector gefällt mir eigentlich ganz gut.

    Aber hier liegt mein Problem:

    vector<char*>DBG;
    DBG.push_back("IRGENDEIN HEADER\r\n"););
    DBG.push_back("Size: 200\r\n");
    

    Ich muss einen request versenden der so aussieht:
    Bsp:
    IRGENDEIN HEADER
    Size: 200

    Und wenn ich meine Vector so zusammenbau wie in dem Beispiel dann funktioniert das mit dem request nicht mehr. 😞


  • Mod

    raw** schrieb:

    Ahh, ich glaub jetzt hab ichs, c_str(); dachte wohl mein string wäre schon zu ende als es das Nullbyte gesehen hat.

    Nein, das überhaupt nichts damit zu tun. Bitte lies die Antworten gründlich.

    Ein Nullbyte Kennzeichnet ja eigentlich auch das string ende ...

    Für Funktionen aus cstring (bzw. string.h) vielleicht. Nicht bei std::string.

    vector<char*>DBG;
    DBG.push_back("IRGENDEIN HEADER\r\n"););
    DBG.push_back("Size: 200\r\n");
    

    So langsam muss ich sagen: Lern C++. Dein Modell und die technische Umsetzung passen überhaupt nicht zusammen. Da liegt offenbar ein großes Missverständnis von Zeichenketten, Standardcontainern und allgemein der Behandlung von Daten vor.

    Du möchtest hier sicherlich einen vector<char> (oder vielleicht doch einen String? Du gibst so wenig Infos und weichst Gegenfragen immer aus). Davon ausgehend gehen die Zuweisungen dann auch komplett anders. Da du vermutlich von C kommst: Ein vector<char*> entspricht einem char**. Dir ist klar, warum das nicht passen kann?



  • raw** schrieb:

    Ok, eine letzte Frage hab ich noch:

    string abc="\x41\x42\x00\x43";
    

    ...

    Da passiert der Fehler. Eine Konstante "foo" schreibt 4 Bytes in den Speicher. Und zwar die 3 Buchstaben und ein null Byte. Wird damit ein std::string erzeugt, sucht der Konstruktor von std::string nach dem ersten null Byte und übernimmt die Zeichen bis dahin.

    Die Konstante "\x41\x42\x00\x43" schreibt eben 5 Bytes in den Speicher. Der Konstruktor sucht hier auch das erste null Byte und findet es aber an der 3. Stelle. Nur die ersten 2 Zeichen \x41 und \x42 werden in den str::string übernommen. Willst Du wirklich alle Zeichen in den std::string übernehmen, geht das mit:

    std::string abc("\x41\x42\x00\x43, 4);
    


  • raw** schrieb:

    Ein Nullbyte Kennzeichnet ja eigentlich auch das string ende ...

    Bei einem C-String wuerde (die C++-Version von) strlen so aussehen:

    template<charT> //Oder so aehnlich. Selbst geschrieben.
    size_t strlen(charT const* ptr)
    {
        size_t rval(0);
        while( ptr++ ) ++rval;
        return rval;
    }
    

    Es wird bis zum ersten Terminierungszeichen (0 oder als character-Literal: '\0') gelesen.
    wie aber sieht std::string::length() aus?

    template< //Oder so aehnlich. Selbst geschrieben.
        typename CharT, 
        typename Traits, 
        typename Allocator
    >
    typename basic_string<CharT, Traits, Allocator>::size_type basic_string::length() const
    {
        return mSize;//Oder so aehnlich
    }
    

    Hier wird ein interner, vorzeichenloser Skalar zurueckgegeben. Was heisst das? std::string speichert die Laenge mit! Und fuer den sind damit Terminierungszeichen irrelevant:

    std::string a(5, '\0'); // Ein String, der aus 5 Nullbytes besteht
    
    std::cout << a.length(); //5
    

    Wieso funktioniert dann folgendes nicht:

    std::string a = "\0\0\0\0\0";
    std::cout << a.length();
    

    Das in der ersten Zeile nennt sich copy-initialisation. Hier wird a der Wert "\0\0\0\0\0" zugewiesen; der entsprechende Konstruktor wird aufgerufen.

    Allerdings kennt dieser Konstruktor die Laenge des uebergebenen C-Strings nicht; er muss ihn also als Null-terminiert betrachten und hoert damit beim ersten Buchstaben auf. Die Laenge ist dementsprechend 0.

    Wie es trotzdem geht?

    char const[] meinScheiss = "\0\0\0\0\0";
    
    std::string a(meinScheiss, meinScheiss + sizeof MeinScheiss); //start-end Iteratorenpaar Konstruktor
    
    std::cout << a.length();
    

    Hier wird 6 herausgegeben. Wieso?
    Sehen wir uns an, was da steht:

    char const[] meinScheiss = "\0\0\0\0\0";
    

    Wird vom Compiler zu

    char const[6] meinScheiss = {'\0', '\0', '\0', '\0', '\0', '\0'};
    

    Geaendert. An die Fuenf Terminierungszeichen wird noch eines rangehaengt (macht der Compiler bei solchen Literalen automatisch).


Anmelden zum Antworten