Wie konstruieren Sie einen std::string mit einer eingebetteten Null?

Lesezeit: 6 Minuten

Wie konstruieren Sie einen stdstring mit einer eingebetteten Null
Rechnung

Wenn ich einen std::string mit einer Zeile wie der folgenden konstruieren möchte:

std::string my_string("a\0b");

Wo ich drei Zeichen in der resultierenden Zeichenfolge haben möchte (a, null, b), bekomme ich nur eines. Was ist die richtige Syntax?

  • Sie müssen damit vorsichtig sein. Wenn Sie ‘b’ durch ein beliebiges numerisches Zeichen ersetzen, erstellen Sie stillschweigend die falsche Zeichenfolge. Siehe: stackoverflow.com/questions/10220401/…

    – David Stein

    14. Oktober 2012 um 16:27 Uhr

1646415610 532 Wie konstruieren Sie einen stdstring mit einer eingebetteten Null
Martin York

Seit C++14

konnten wir erstellen wörtlich std::string

#include <iostream>
#include <string>

int main()
{
    using namespace std::string_literals;

    std::string s = "pl-\0-op"s;    // <- Notice the "s" at the end
                                    // This is a std::string literal not
                                    // a C-String literal.
    std::cout << s << "\n";
}

Vor C++14

Das Problem ist die std::string Konstruktor, der a nimmt const char* geht davon aus, dass die Eingabe ein C-String ist. C-Saiten sind \0 beendet und somit stoppt das Parsen, wenn es die erreicht \0 Charakter.

Um dies zu kompensieren, müssen Sie den Konstruktor verwenden, der die Zeichenfolge aus einem char-Array (kein C-String) erstellt. Dies erfordert zwei Parameter – einen Zeiger auf das Array und eine Länge:

std::string   x("pq\0rs");   // Two characters because input assumed to be C-String
std::string   x("pq\0rs",5); // 5 Characters as the input is now a char array with 5 characters.

Hinweis: C++ std::string ist NICHT \0-beendet (wie in anderen Beiträgen vorgeschlagen). Sie können jedoch mit der Methode einen Zeiger auf einen internen Puffer extrahieren, der einen C-String enthält c_str().

Sehen Sie sich auch die Antwort von Doug T unten zur Verwendung von a an vector<char>.

Sehen Sie sich auch RiaD für eine C++14-Lösung an.

  • Update: Ab c++11 sind Strings nullterminiert. Davon abgesehen bleibt Lokis Post gültig.

    – matthewaveryusa

    12. August 2014 um 3:08 Uhr


  • @mna: Sie sind in Bezug auf die Speicherung nullterminiert, aber nicht in dem Sinne, dass sie nullterminiert sind mit sinnvoller Nullterminierung (dh mit zeichenfolgenlängendefinierender Semantik), was die übliche Bedeutung des Begriffs ist.

    – Leichtigkeitsrennen im Orbit

    17. Juni 2015 um 15:50 Uhr

  • Gut erklärt. Danke.

    – Joma

    25. Oktober 2018 um 4:39 Uhr

Wie konstruieren Sie einen stdstring mit einer eingebetteten Null
Doug T.

Wenn Sie Manipulationen vornehmen, wie Sie es mit einer Zeichenfolge im C-Stil (Array von Zeichen) tun würden, sollten Sie die Verwendung von in Betracht ziehen

std::vector<char>

Sie haben mehr Freiheit, es wie ein Array zu behandeln, genauso wie Sie einen C-String behandeln würden. Sie können copy() verwenden, um in einen String zu kopieren:

std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());

und Sie können es an vielen Stellen verwenden, an denen Sie C-Strings verwenden können

printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';

Sie leiden aber natürlich unter den gleichen Problemen wie C-Saiten. Sie können Ihr Nullterminal vergessen oder über den zugewiesenen Platz hinaus schreiben.

  • Wenn Sie sagen, dass Sie versuchen, Bytes in Zeichenfolgen zu codieren (grpc-Bytes werden als Zeichenfolge gespeichert), verwenden Sie die Vektormethode, wie in der Antwort angegeben. nicht auf die übliche Weise (siehe unten), die NICHT die gesamte Zeichenfolge erstellt byte *bytes = new byte[dataSize]; std::memcpy(bytes, image.data, dataSize * sizeof(byte)); std::string test(reinterpret_cast<char *>(bytes)); std::cout << "Encoded String length " << test.length() << std::endl;

    – Alex Punnen

    29. Juli 2018 um 14:07 Uhr


Ich habe keine Ahnung warum Sie würden so etwas tun wollen, aber versuchen Sie Folgendes:

std::string my_string("a\0b", 3);

  • Was sind Ihre Bedenken, dies zu tun? Stellen Sie die Notwendigkeit in Frage, “a\0b” jemals zu speichern? oder die Verwendung eines std::string für eine solche Speicherung in Frage stellen? Wenn letzteres, was schlagen Sie als Alternative vor?

    – Anthony Krampf

    3. Oktober 2008 um 0:08 Uhr

  • @Constantin dann machst du etwas falsch, wenn du Binärdaten als String speicherst. Das ist, was vector<unsigned char> oder unsigned char * wurden für erfunden.

    – Mahmoud Al-Qudsi

    4. Januar 2012 um 23:25 Uhr


  • Ich bin darauf gestoßen, als ich versuchte, mehr über die Sicherheit von Saiten zu erfahren. Ich wollte meinen Code testen, um sicherzustellen, dass er auch dann noch funktioniert, wenn er ein Nullzeichen liest, während er aus einer Datei / einem Netzwerk liest, was er als Textdaten erwartet. ich benutze std::string um anzuzeigen, dass die Daten als Klartext betrachtet werden sollten, aber ich mache einige Hash-Arbeiten und möchte sicherstellen, dass alles immer noch mit beteiligten Nullzeichen funktioniert. Das scheint eine gültige Verwendung eines Zeichenfolgenliterals mit einem eingebetteten Nullzeichen zu sein.

    – David Stein

    19. April 2012 um 0:41 Uhr

  • @DuckMaestro Nein, das stimmt nicht. EIN \0 Byte in einem UTF-8-String kann nur NUL sein. Ein Multi-Byte-codiertes Zeichen wird niemals enthalten \0–noch irgendein anderes ASCII-Zeichen für diese Angelegenheit.

    – John Kugelmann

    26. September 2013 um 12:55 Uhr

  • Ich bin darauf gestoßen, als ich versuchte, einen Algorithmus in einem Testfall zu provozieren. Es gibt also triftige Gründe; wenn auch wenige.

    – Namensnull

    14. November 2014 um 11:16 Uhr

1646415611 346 Wie konstruieren Sie einen stdstring mit einer eingebetteten Null
Andreas Stein

Folgendes wird funktionieren…

std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');

Wie konstruieren Sie einen stdstring mit einer eingebetteten Null
David Stein

Sie müssen damit vorsichtig sein. Wenn Sie „b“ durch ein beliebiges numerisches Zeichen ersetzen, erstellen Sie mit den meisten Methoden stillschweigend die falsche Zeichenfolge. Siehe: Regeln für Escape-Zeichen für C++-String-Literale.

Zum Beispiel habe ich diesen unschuldig aussehenden Schnipsel mitten in einem Programm abgelegt

// Create '\0' followed by '0' 40 times ;)
std::string str("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", 80);
std::cerr << "Entering loop.\n";
for (char & c : str) {
    std::cerr << c;
    // 'Q' is way cooler than '\0' or '0'
    c="Q";
}
std::cerr << "\n";
for (char & c : str) {
    std::cerr << c;
}
std::cerr << "\n";

Hier ist, was dieses Programm für mich ausgibt:

Entering loop.
Entering loop.

vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ

Das war zweimal meine erste Druckanweisung, mehrere nicht druckbare Zeichen, gefolgt von einem Zeilenumbruch, gefolgt von etwas im internen Speicher, das ich gerade überschrieben habe (und dann gedruckt habe, um zu zeigen, dass es überschrieben wurde). Am schlimmsten war, dass selbst das Kompilieren mit gründlichen und ausführlichen gcc-Warnungen mir keinen Hinweis darauf gab, dass etwas nicht stimmte, und das Ausführen des Programms durch valgrind beschwerte sich nicht über fehlerhafte Speicherzugriffsmuster. Mit anderen Worten, es ist für moderne Tools völlig unauffindbar.

Sie können das gleiche Problem mit dem viel einfacheren bekommen std::string("0", 100);aber das obige Beispiel ist etwas kniffliger und daher schwerer zu erkennen, was falsch ist.

Glücklicherweise bietet uns C++11 eine gute Lösung für das Problem, indem es die Initialisierungslistensyntax verwendet. Dies erspart Ihnen die Angabe der Zeichenanzahl (was Sie, wie ich oben gezeigt habe, falsch machen kann) und vermeidet das Kombinieren von Zahlen mit Escapezeichen. std::string str({'a', '\0', 'b'}) ist sicher für jeden String-Inhalt, im Gegensatz zu Versionen, die ein Array von verwenden char und eine Größe.

  • Als Teil meiner Vorbereitung auf diesen Beitrag habe ich einen Fehlerbericht an gcc gesendet, in der Hoffnung, dass sie eine Warnung hinzufügen, um dies ein wenig sicherer zu machen: gcc.gnu.org/bugzilla/show_bug.cgi?id=54924

    – David Stein

    14. Oktober 2012 um 17:07 Uhr

1646415612 126 Wie konstruieren Sie einen stdstring mit einer eingebetteten Null
RiaD

In C++14 können Sie jetzt Literale verwenden

using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3

  • Als Teil meiner Vorbereitung auf diesen Beitrag habe ich einen Fehlerbericht an gcc gesendet, in der Hoffnung, dass sie eine Warnung hinzufügen, um dies ein wenig sicherer zu machen: gcc.gnu.org/bugzilla/show_bug.cgi?id=54924

    – David Stein

    14. Oktober 2012 um 17:07 Uhr

Verwenden Sie besser std::vector, wenn diese Frage nicht nur für Bildungszwecke dient.

937150cookie-checkWie konstruieren Sie einen std::string mit einer eingebetteten Null?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy