/ / Rozszyfrowanie niepodpisanego znaku * - c ++, linux

Odszyfrowanie niepodpisanego znaku * - c ++, linux

Mam proces, który słucha transmisji rozgłoszeniowej UDP i odczytuje dane jako niepodpisany znak *.

Mam specyfikację, która wskazuje pola w obrębie tego niepodpisanego znaku *.

Pola są zdefiniowane w specyfikacji z typem i rozmiarem.

Typy: uInt32, uInt64, unsigned int i jednobajtowy łańcuch.

W przypadku ciągu jednobajtowego mogę jedynie uzyskać dostęp do przesunięcia pola w niepodpisanym znaku * i przesłać do znaku, na przykład:

char character = (char)(data[1]);

Pojedynczy bajt uint32 wykonuję następujące czynności, które również wydają się działać:

uint32_t integer =  (uint32_t)(data[20]);

Jednak w przypadku konwersji wielobajtowych wydaje mi się, że utknąłem.

Jak przekonwertować kilka bajtów z rzędu (podciąg z data) do odpowiedniego typu danych?

Czy bezpieczne jest zawijanie danych w łańcuchu (w celu wykorzystania funkcji podłańcuchowych)? Martwię się o utratę informacji, ponieważ będę musiał rzucić niepodpisany znak * na char *, na przykład:

std::string wrapper((char*)(data),length); //Is this safe?

Próbowałem coś takiego:

std::string wrapper((char*)(data),length); //Is this safe?
uint32_t integer = (uint32_t)(wrapper.substr(20,4).c_str()); //4 byte int

Ale to nie działa.

Myśli?


Aktualizacja

Próbowałem przesunięcia bitowego sugerowania:

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]);
}

To niestety daje mi śmieci (ten sam numer dla każdego połączenia - od callbacka).

Odpowiedzi:

2 dla odpowiedzi № 1

Myślę, że powinieneś być bardzo jednoznaczny, i nie po prostu rób "sprytne" sztuczki za pomocą rzutów i wskaźników. Zamiast tego napisz taką funkcję:

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];
}

To wyodrębnia pojedynczą wartość uint32_t z bufora o niepodpisanym znaku i zwiększa wskaźnik bufora do punktu na następnym bajcie danych w buforze.

Zakłada to dane big-endian, musisz mieć dobrze zdefiniowaną koncepcję trybu endianowego bufora, aby go zinterpretować.


2 dla odpowiedzi nr 2

Zależy od kolejności bajtów protokołu, w przypadku wielobajtowej lub tzw. Kolejności bajtów sieciowych:

uint32_t i = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];

0 dla odpowiedzi № 3

Bez komentowania, czy jest to dobry pomysł, czy nie, powodem, dla którego nie działa on dla ciebie, jest to, że wynikiem wrapper.substring (20,4) .c_str () jest (uint32_t *), a nie (uint32_t). Jeśli więc:

uint32_t * integer = (uint32_t *) (wrapper.substr (20,4) .c_str (); powinno działać.


0 dla odpowiedzi nr 4
uint32_t integer = ntohl(*reinterpret_cast<const uint32_t*>(data + 20));

lub (obsługuje problemy z wyrównaniem):

uint32_t integer;
memcpy(&integer, data+20, sizeof integer);
integer = ntohl(integer);

0 dla odpowiedzi № 5

Wskaźnik:

uint32_t n = *(uint32_t*)&data[20];

Jednak napotkasz problemy na różnych architekturach endian. Rozwiązanie z przesunięciami bitowymi jest lepsze i spójne.

std::string wrapper((char*)(data),length); //Is this safe?

To powinno być bezpieczne, ponieważ podałeś długość danych. Z drugiej strony, jeśli to zrobiłeś:

std::string wrapper((char*)data);

Długość łańcucha zostanie określona w miejscu, w którym wystąpi pierwszy 0 bajtów, a użytkownik prawdopodobnie zetnie trochę danych.