2010-12-07 4 views
1

Je pense que c'est un problème assez simple, mais je ne peux toujours pas le comprendre.ajouter et supprimer d'un (void *) dans C

J'ai une fonction qui envoie un flux sur le réseau. naturellement, cela prend const void * comme argument:

void network_send(const void* data, long data_length) 

je suis en train de préfixer un en-tête spécifique sous la forme de char * à cela avant de l'envoyer sur le socket:

long sent_size = strlen(header)+data_length; 
    data_to_send = malloc(sent_size); 
    memcpy(data_to_send,header,strlen(header)); /*first copy the header*/ 
    memcpy((char*)data_to_send+strlen(header),data,dat_length); /*now copy the actual data*/ 

Cela fonctionne bien aussi longtemps que les données sont réellement char *. mais s'il change à un autre type de données, alors cela cesse de fonctionner.

Lors de la réception, j'ai besoin de supprimer l'en-tête des données avant de le traiter. voici comment il le fait:

void network_data_received(const void* data, long data_length) 
{ 
........ 
memmove(data_from_network,(char*)data_from_network + strlen(header),data_length); /*move the data to the beginning of the array*/ 
ProcessFurther(data_from_network ,data_length - strlen(header)) /*data_length - strlen(header) causes the function ProcessFurther to read only certain part of the array*/ 
} 

Cela fonctionne à nouveau bien si les données sont de type char. mais se bloque s'il est de type différent.

Quelqu'un peut-il suggérer comment implémenter correctement cela?

Cordialement, Khan

+0

Comment appelez-vous ces fonctions? Pouvez-vous fournir le code? – detunized

+2

Vous ne calculez pas data_length en utilisant 'strlen', n'est-ce pas? Est-ce vraiment la bonne fonction pour votre tête aussi? – Rup

+0

le problème réside dans l'utilisation (char *) Data_to_Send + strlen (tête) –

Répondre

0

en utilisant unsigned char * a résolu le problème. Merci à tous pour vos commentaires.

0

vous devriez utiliser memmove()

comportement de memcpy est indéfini si la source et le chevauchement cible (comme dans ce cas) Qu'est-ce qui se passe exactement quand ce n'est pas char*? Ces fonctions sont généralement converties en void* avant d'effectuer tout travail ...

+0

quand il n'est pas char *, il fonctionne toujours, mais à la réception, il est foiré. parce que les données sont cryptées (cryptage XOR très simple). il ya essentiellement deux types de données ici: char * unsigned * donc je pense que j'ai besoin de jeter void * à un type qui fonctionne pour les deux. mon knowlefge en C++ est limité en raison de l'absence d'utilisation –

2

L'alignement peut poser problème, mais vous ne spécifiez pas sur quelle plate-forme vous effectuez cette opération (différentes architectures de processeur ont des exigences d'alignement différentes). .

Si la longueur de l'en-tête est "incorrecte" pour l'alignement des données suivantes, cela pourrait entraîner des violations d'accès.

+0

l'alignement est le problème en fait, car parfois j'obtiens un accès mémoire invalide quand les données sont de type non signé *. –

2

Quelque chose me surprend dans ce code. Est-ce que votre en-tête est une chaîne? Si c'est une structure, de quelque chose de similaire, vous devriez remplacer strlen par sizeof. Appeler strlen sur une chaîne terminée non nulle est susceptible de provoquer des plantages. La deuxième chose qui me surprend est que lors de la lecture des données reçues, vous devez copier l'en-tête quelque part. Si vous ne l'utilisez pas, pourquoi s'empresser de l'envoyer sur le fil?

EDIT: OK, l'en-tête est une chaîne d'en-tête de type http. Il ne devrait pas y avoir de problème à partir de là, et il n'a en effet pas besoin d'être analysé si vous testez simplement.

Et vous devriez déplacer les données à l'endroit où vous en avez réellement besoin, le déplacer au début du tampon ne semble pas être la bonne chose à faire.

Si le problème provient de l'alignement, il disparaîtra si vous copiez les données dans une variable du type cible réel au niveau octet avant de l'utiliser.

Il existe une autre solution: allouer votre tampon avec malloc et mettre la structure de données que vous voulez au début. Ensuite, vous devriez être capable de le lancer. Les adresses renvoyées par malloc sont compatibles avec n'importe quel type.

Sachez également que si vous utilisiez C++, la conversion vers une classe non triviale a peu de chances de fonctionner (d'une part, vtables risque d'obtenir une adresse erronée et d'autres problèmes).

Une autre source possible de problème est la façon dont vous obtenez data_length. Cela devrait être un nombre d'octets. Êtes-vous sûr que ce n'est pas un nombre d'articles? Pour être sûr que nous avons besoin de quelques indices sur le code d'appel.

+0

l'en-tête est: statique const char * tête = "GET /images/logo.gif \ r \ n HTTP/1.1 \ r \ n Accepter:../\ R \ n Référent:. Google.com \ r \ n Accept-Language: en-us. \ R \ n Données: " –

0

Il est possible que data_length est pas correctement calculé dans le code d'appel. Sinon, ce code semble être bon en dehors des problèmes d'alignement possibles mentionnés par @unwind.

Comment est header déclarée? A-t-il une longueur variable? Vous manquez un caractère de fin NUL après le header?

+0

l'en-tête est déclaré comme ceci: static const char * header =" GET /images/logo.gif \ r \ n HTTP/1.1. \ R \ n Accepter: */*. \ R \ n Référent: http://www.google.com/. \ R \ n Accept-Language: en-us. \ R \ n Données: "; il est une longueur constante de 122. En-tête infact n'est pas le problème, la conversion en (char *) provoque le problème –

0

Je vérifie également vous assurer que l'expéditeur et le récepteur utilisent la même architecture de l'ordre des octets (petit-boutiste vs big endian).

Questions connexes