/ / Déchiffrement du caractère non signé * - c ++, linux

Déchiffrer le caractère non signé * - c ++, linux

J'ai un processus qui écoute une diffusion UDP multidiffusée et lit les données sous la forme d'un caractère non signé *.

J'ai une spécification qui indique les champs dans ce caractère non signé *.

Les champs sont définis dans la spécification avec un type et une taille.

Les types sont: uInt32, uInt64, unsigned int et chaîne à un octet.

Pour la chaîne à un octet, je peux simplement accéder au décalage du champ dans le caractère non signé * et le convertir en caractère tel que:

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

Seul octet uint32, j’ai effectué les opérations suivantes, ce qui semble également fonctionner:

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

Cependant, pour les conversions sur plusieurs octets, il semble que je sois bloqué.

Comment convertir plusieurs octets à la suite (sous-chaîne de data) à son type de données correspondant?

De même, est-il prudent d’envelopper des données dans une chaîne (pour l’utilisation de la fonctionnalité de sous-chaîne)? Je suis inquiet de perdre des informations, car je devrais lancer un caractère non signé *, tel que:

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

J'ai essayé quelque chose comme ça:

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

Mais ça ne marche pas.

Pensées?


Mettre à jour

J'ai essayé le changement de bit suggéré:

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

Cela me donne malheureusement des ordures (même numéro pour chaque appel - depuis un rappel).

Réponses:

2 pour la réponse № 1

Je pense que vous devriez être très explicite, et ne pas Il suffit de faire "astucieux" astuces avec des lancers et des pointeurs. Au lieu de cela, écrivez une fonction comme celle-ci:

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

Cela extrait une seule valeur uint32_t à partir d'un tampon de caractères non signés et augmente le pointeur de tampon pour qu'il pointe vers l'octet suivant de données dans le tampon.

Cela suppose des données big-endian, vous devez avoir une idée bien définie du mode endian du tampon afin de l’interpréter.


2 pour la réponse № 2

Dépend de l'ordre des octets du protocole, pour l'ordre des octets de réseau appelé big-endian:

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

0 pour la réponse № 3

Sans préciser si c'est une bonne idée ou non, la raison pour laquelle cela ne fonctionne pas pour vous est que le résultat de wrapper.substring (20,4) .c_str () est (uint32_t *), pas (uint32_t). Donc si vous le faites:

uint32_t * entier = (uint32_t *) (wrapper.substr (20,4) .c_str (); cela devrait fonctionner.


0 pour la réponse № 4
uint32_t integer = ntohl(*reinterpret_cast<const uint32_t*>(data + 20));

ou (gère les problèmes d'alignement):

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

0 pour la réponse № 5

Le chemin du pointeur:

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

Vous rencontrerez cependant des problèmes sur différentes architectures Endian. La solution avec des changements de bits est meilleure et cohérente.

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

Cela devrait être sûr puisque vous avez spécifié la longueur des données. Par contre si vous faisiez ceci:

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

La longueur de la chaîne serait déterminée chaque fois que le premier octet 0 se produirait, et vous aurez plus que probablement besoin de couper certaines données.