Ich habe einen Prozess, der eine UDP-Multicast-Übertragung abhört und die Daten als nicht signiertes Zeichen * einliest.
Ich habe eine Spezifikation, die Felder innerhalb dieses vorzeichenlosen Zeichens * angibt.
Felder sind in der Spezifikation mit einem Typ und einer Größe definiert.
Typen sind: uInt32, uInt64, unsigned int und Einzelbytezeichenfolge.
Für die Einzelbyte-Zeichenfolge kann ich lediglich auf den Offset des Felds im vorzeichenlosen Zeichen * zugreifen und in ein Zeichen konvertieren, z.
char character = (char)(data[1]);
Singlebyte uint32 Ich habe Folgendes getan, was auch zu funktionieren scheint:
uint32_t integer = (uint32_t)(data[20]);
Bei Mehrfach-Byte-Konvertierungen scheine ich jedoch festzuhalten.
Wie würde ich mehrere Bytes hintereinander konvertieren? data
) zu seinem entsprechenden Datentyp?
Ist es außerdem sicher, Daten in eine Zeichenfolge einzuwickeln (für die Verwendung der Teilzeichenfolge)? Ich bin besorgt darüber, Informationen zu verlieren, da ich unsigniertes Zeichen * an Zeichen * übergeben müsste, wie:
std::string wrapper((char*)(data),length); //Is this safe?
Ich habe so etwas versucht:
std::string wrapper((char*)(data),length); //Is this safe?
uint32_t integer = (uint32_t)(wrapper.substr(20,4).c_str()); //4 byte int
Aber es funktioniert nicht.
Gedanken?
Aktualisieren
Ich habe versucht, die Bitverschiebung vorzuschlagen:
void function(const unsigned char* data, size_t data_len)
{
//From specifiction: Field type: uInt32 Byte Length: 4
//All integer fields are big endian.
uint32_t integer = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3]);
}
Das gibt mir leider Müll (gleiche Nummer für jeden Anruf - von einem Rückruf).
Antworten:
2 für die Antwort № 1Ich denke, Sie sollten sehr deutlich sein, und nicht Machen Sie einfach "clevere" Tricks mit Casts und Zeigern. Schreiben Sie stattdessen eine Funktion wie folgt:
uint32_t read_uint32_t(unsigned char **data)
{
const unsigned char *get = *data;
*data += 4;
return (get[0] << 24) | (get[1] << 16) | (get[2] << 8) | get[3];
}
Dies extrahiert einen einzelnen uint32_t-Wert aus einem Puffer mit vorzeichenlosen Zeichen und erhöht den Pufferzeiger, um auf das nächste Datenbyte im Puffer zu zeigen.
Dies setzt voraus, dass Big-Endian-Daten vorliegen. Sie müssen eine genaue Vorstellung vom Endian-Modus des Puffers haben, um sie interpretieren zu können.
2 für die Antwort № 2
Abhängig von der Bytereihenfolge des Protokolls, für Big-Endian oder sogenannte Netzwerk-Bytereihenfolge:
uint32_t i = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
0 für die Antwort № 3
Ohne zu kommentieren, ob es eine gute Idee ist oder nicht, besteht der Grund, warum es für Sie nicht funktioniert, darin, dass das Ergebnis von wrapper.substring (20,4) .c_str () (uint32_t *) und nicht (uint32_t) ist. Also wenn du es tust:
uint32_t * integer = (uint32_t *) (wrapper.substr (20,4) .c_str (); es sollte funktionieren.
0 für die Antwort № 4
uint32_t integer = ntohl(*reinterpret_cast<const uint32_t*>(data + 20));
oder (behandelt Ausrichtungsprobleme):
uint32_t integer;
memcpy(&integer, data+20, sizeof integer);
integer = ntohl(integer);
0 für die Antwort № 5
Der Zeigerweg:
uint32_t n = *(uint32_t*)&data[20];
Sie werden jedoch auf verschiedenen Endian-Architekturen auf Probleme stoßen. Die Lösung mit Bitverschiebungen ist besser und konsistenter.
std::string wrapper((char*)(data),length); //Is this safe?
Dies sollte sicher sein, da Sie die Länge der Daten angegeben haben. Andererseits, wenn Sie dies getan haben:
std::string wrapper((char*)data);
Die Länge des Strings würde überall dort bestimmt, wo das erste 0-Byte vorkommt, und Sie werden wahrscheinlich einige Daten abschneiden.