Protokollanleitung als fertiges Paket schreiben
-
Hey Doc!
ich bin auf ein Problem gestossen. Wenn
die SequenceID 0x00000001 ist dann baue
ich mir doch in den stringstream ungewollt einen wertlosen stringterminator ein (0x00)
-
In meinem Code taucht nirgendwo ein
stringstream
auf, also musst du was dazugebastelt haben.
-
Sorry
ich meinte den ostringstream
-
Werd´ bitte mal etwas genauer, ich habe keine Ahnung, wo dein Problem liegt.
-
Es geht um folgendes Statement:
You are using std::strings, and ostringstreams, to construct and contain a sequence of bytes. This works as long as you don't try to put any 0x00 bytes into the sequence. Once you start doing so, you are on very shaky ground.
Either the resulting sequence will get cut off at the first 0x00 byte, or mystring.size() will be larger than strlen(mystring.c_str()). That way lies madness and bugs that are difficult to track down.
Besides, you are aware that the 'char' datatype may be either signed or unsigned, depending on which compiler you are using? Normally it is signed. This does not cause any problems for the code that builds the sequence, but may cause problems for the code that decodes a sequence into C++ datastructures.
You are better off using an std::vector<uint8_t> as your container, dropping the ostringstream, and using some custom code for constructing the sequence.
Ist diese Aussage richtig oder falsch?
-
Es trifft hier vor allem nicht zu. Es geht darum, dass
std::string
durchaus Nullbytes enthalten kann und dassstd::string::c_str()
einen Zeiger auf einen linearen Puffer des Stringinhalts zurückgibt. Damit kommen die C-Funktionen natürlich nicht klar, aber wer Konstruktionen wiestd::string s = "Mächtiger Badabumm"; unsigned int len = strlen( s.c_str() );
benutzt hat eh´ nicht mehr alle Latten am Zaun. Du solltest inzwischen gemerkt haben, dass man genau wissen muss, was man programmiert. Wenn du C++ und C Funktionen so mischst, dass Fehler entstehen, dann weißt du´s offensichtlich gerade nicht.
In dem ganzen Code, den ich hier gepostet habe, tritt der Fall nie auf. Wie kommst du also darauf?
-
Hmmm, ich frage mich gerade warum dieser
negative Unterton. Ich habe doch nur
freundlich eine Frage gestellt, zahle
meine Steuern pünktlich und tuhe auch
sonst keiner Fliege was zu leide.Ich wurde in einem Forum von einem
User gefragt, ob ich ein C++ Beispiel habe
um ein Paket mit den gegebenen Anforderungen zu erstellen. Als
Beispiel habe ich ihm deinen
unveränderten Code gezeigt ohne
includes und ohne main().
Daraufhin hat sich einer der
Chefentwickler von EA Games
mit dem oben genannten Statement
geäussert. Daraufhin fühlte ich
mich verunsichert und wollte
dich nochmal Fragen, Gott verzeihe.Es geht in keinsterweisse um meinen Code.
-
Ich hab jetzt einen Testcode aufgebaut um sein Statement nachzubilden. Resultat des ganzen ist, dass ich seine Befürchtung mit 0x00 in einem String egal welcher Art theoretisch nachvollziehen kann aber in der Praxis mit deinem Code vollkommen irrelevant ist.
Er schrieb folgendes:
// Write Sequence ID oss << static_cast<char>( Sequence & 0xff ) << static_cast<char>( (Sequence >> 8) & 0xff ) << static_cast<char>( (Sequence >> 16) & 0xff ) << static_cast<char>( (Sequence >> 24) & 0xff );
That bit right there takes a 32-byte integer, splits it up into 4 bytes, and stuffs each of the 4 bytes into an ostringstream object. Raw. So if Sequence == 0x00000001, the code will be stuffing 0x00's into the ostringstream.
Also quoting from above,
// Write terminating 0 oss << static_cast<char>( 0 );
This will clearly stuff an 0x00 into the ostringstream.
Both these code sections violate the principle: do not stuff 0x00s into strings.
Darauf hin habe ich folgendes Versucht:
std::vector<std::string> Words; Words.push_back("login.plainText"); Words.push_back("mypassword"); std::string Packet = make_packet( 0x00000001, Words );
.....funktioniert.
std::string Packet = make_packet( 0x00, Words );
....funktioniert
std::string Packet = make_packet( 1, Words );
.....funktioniert.
-
Zero01 schrieb:
Ist diese Aussage richtig oder falsch?
Beides.
std::string kann mit Nullbytes umgehen und wird auch so verwendet. Auch in gängiger C++ Fachliteratur (z.B. Scott Meyers) steht nichts darüber, dass man das nicht tun soll.
Was dieser angebliche "Chefprogrammierer" da schreibt:
Zero01 schrieb:
Both these code sections violate the principle: do not stuff 0x00s into strings.
ist eine hausinterne Regel, die jemand braucht, der so etwas wie
unsigned int len = strlen( s.c_str() );
schreibt.
Dass der, wie DocShoe schreibt, nicht alle Latten am Zaun hat, ist Realität und kein negativer Unterton.
Auch C-Strings können Nullbytes enthalten:
char* pc = "ABC\0abc";
Es gibt genügend Anwendungen, wo das vorkommt. Was mach der "Chefprogrammierer" dann ?
-
Jetzt fühl´ dich nicht gleich auf den Schlips getreten, ich habe weder behauptet, dass du Steuern hinterziehst noch irgendwie anders kriminell bist.
C++ ist nun mal ein Sprache, die Vieles erlaubt und damit auch viele Möglichkeiten bietet, etwas falsch zu machen. Deshalb schrieb ich ja schon mehrmals, dass man genau wissen muss, was man tut. Wenn ich weiß, dass eine Sequence Binärdaten enthält, dann sollte ich da keinstrlen
draufloslassen, weil eben genau der Fall eintreten kann, dass irgendwo mittendrin Nullbytes stehen. Und dann liefertstrlen
nicht das zurück, was man haben will. Für jedes Problem das richtige Werkzeug, und in diesem Fall iststrlen
nicht das richtige Werkzeug. Im übrigen gehtstd::vector<uint_8t> MyVec = ...; unsigned int len = strlen( &MyVec[0] );
genauso in die Hose, wenn der Vektor Nullbytes in der Mitte enthält.
Der EA Chefprogrammierer assoziiert mit
std::string
wohl ein gekapseltes C-String Pendant. Dabei iststd::string
wesentlich mächtiger als C-Strings, und das habe ich in meinem Code bewusst ausgenutzt. Du kannst stattdessen natürlich auch einenstd::vector<unsigned char>
benutzen, wenn es dir besser gefällt:std::vector<char> Buffer; std::string Word; Buffer.push_back( static_cast<char>( SequenceID & 0xff ) ); Buffer.push_back( static_cast<char>( SequenceID >> 8) & 0xff ); Buffer.push_back( static_cast<char>( SequenceID >> 16) & 0xff ); Buffer.push_back( static_cast<char>( SequenceID >> 24) & 0xff ); Buffer.insert( Buffer.end(), Word.begin(), Word.end() ); ...
aber da gefällt mir das
ostream
Interface wesentlich besser.Mit gleichem Argument könnte ich die Benutzung von iteratoren verbieten, da dieser Code zwar kompiliert, aber zu UB führt, was ziemlich knifflig zu debuggen ist:
std::vector<int> v =...; std::sort( v.end(), v.begin() );
-
Danke Jungs für die Aufklärung. Jetzt
wo ich dagegen argumentiert habe, hüllt
sich dieser Mensch in schweigen.Die Aufruf um den std::string als
konstanten c_string zu lesen
um die strlen zu bestimmen is eh unfug.
Wofür haben wir dann das Bordmittel
.size() was keinerlei Sprachvermischung
benötigt.Nichts für ungut, ich war doch gar nich
sauer.
-
Danke Jungs für die Aufklärung. Jetzt
wo ich dagegen argumentiert habe, hüllt
sich dieser Mensch in schweigen.Die Aufruf um den std::string als
konstanten c_string zu lesen
um die strlen zu bestimmen is eh unfug.
Wofür haben wir dann das Bordmittel
.size() was keinerlei Sprachvermischung
benötigt.Nichts für ungut, ich war doch gar nich
sauer.