Comment convertir un tableau struct en char en C
Je suis en train de convertir en une structure de type char tableau à envoyer sur le réseau. Cependant, je reçois un peu bizarre de sortie à partir du char tableau lorsque je fais.
#include <stdio.h>
struct x
{
int x;
} __attribute__((packed));
int main()
{
struct x a;
a.x=127;
char *b = (char *)&a;
int i;
for (i=0; i<4; i++)
printf("%02x ", b[i]);
printf("\n");
for (i=0; i<4; i++)
printf("%d ", b[i]);
printf("\n");
return 0;
}
Voici les résultats pour différentes valeurs de un.x (sur un système X86 à l'aide de gcc):
127:
7f 00 00 00
127 0 0 0
128:
ffffff80 00 00 00
-128 0 0 0
255:
ffffffff 00 00 00
-1 0 0 0
256:
00 01 00 00
0 1 0 0
Je comprends les valeurs de 127 et 256, mais pourquoi les numéros de changement lorsque l'on va à 128? Pourquoi ne serait-il pas simplement être:
80 00 00 00
128 0 0 0
Suis-je oublier de faire quelque chose dans le processus de conversion ou suis-je oublier quelque chose au sujet de représentation entière?
*Note: Ceci est juste un petit programme de test. Dans un vrai programme, j'ai plus dans la structure, mieux les noms de variables, et je convertir pour little-endian.
*Edit: mise en forme
source d'informationauteur falcojr
Vous devez vous connecter pour publier un commentaire.
La
x
spécificateur de format par lui-même dit que l'argument est unint
et depuis le nombre est négatif,printf
nécessite de huit caractères pour afficher tous les quatre non-zéro octets de laint
de la taille de la valeur. Le0
modificateur dit à la map la sortie avec des zéros, et la2
modificateur dit que le minimum de sortie devrait être de deux caractères. Aussi loin que je peux dire,printf
ne fournit pas un moyen de spécifier un maximum largeur, sauf pour les chaînes.Maintenant, vous, vous êtes seulement de passage d'un
char
si nux
indique la fonction à utiliser le pleinint
qui s'est passé au lieu — en raison de l'argument par défaut de la promotion pour "...
" paramètres". Essayez lehh
modificateur de dire à la fonction pour traiter l'argument comme juste unchar
à la place:Ce que vous voyez est le signe de la préservation de la conversion de char en int. Le comportement s'explique par le fait que sur votre système, le char est signé (Remarque: char n'est pas signé sur tous les systèmes). Qui va conduire à des valeurs négatives si un peu-modèle à rendements d'une valeur négative pour un char. La promotion d'un tel char int permettra de préserver le signe et l'int sera négatif. Notez que même si vous ne mettez pas un
(int)
explicitement, le compilateur va automatiquement promouvoir le caractère d'un int lors du passage à printf. La solution est de convertir votre valeur àunsigned char
première:Alternativement, vous pouvez utiliser
unsigned char*
depuis le début de la:Et puis vous n'avez pas besoin de n'importe quelle distribution au moment de l'impression avec printf.
char est un type signé; donc, avec en complément à deux, 0x80 est -128 pour un entier 8 bits (c'est à dire un octet)
Le traitement de votre structure, comme si il s'agissait d'un char tableau est un comportement indéfini. Pour l'envoyer sur le réseau, utilisez le bon de sérialisation à la place. C'est une douleur en C++ et encore plus en C, mais c'est la seule façon de votre app, vous permettra de travailler de façon indépendante des machines, de la lecture et de l'écriture.
http://en.wikipedia.org/wiki/Serialization#C
La conversion de votre structure de caractères ou d'octets de la façon dont vous le faites, va entraîner des problèmes lorsque vous essayez de le rendre réseau neutre. Pourquoi ne pas s'attaquer à ce problème maintenant? Il existe une variété de différentes techniques que vous pouvez utiliser, qui sont susceptibles d'être plus "portable" que ce que vous essayez de faire. Par exemple:
htonl
htons
ntohl
etntohs
. Voir, par exemple, la byteorder(3) page de manuel sur un FreeBSD ou Linux.char est un type signé donc ce que vous voyez est le deux-compliment de la représentation, de la coulée (unsigned char*) va corriger ça (Rowland vient de battre moi).
Sur une note de côté, vous voudrez changer
à
La ce paramètre de char tableau n'est pas à la racine du problème! (C'est un problème, mais pas le seul problème.)
De l'alignement! C'est le mot clé ici. C'est pourquoi vous ne devez JAMAIS essayer de traiter des structures comme la mémoire brute. Cas de déviation (et l'optimisation des différents drapeaux), systèmes d'exploitation, et les phases de la lune n'étrange et passionnant choses à l'emplacement réel dans la mémoire des "à côté" les champs de la structure. Par exemple, si vous avez une structure avec un char, suivi par un int, l'ensemble de la structure sera de HUIT octets en mémoire -- le char, 3 vide, inutile octets et 4 octets pour l'int. La machine aime faire des choses comme cela, afin que les structures peuvent s'adapter correctement sur les pages de la mémoire, et telles.
Prendre un cours d'introduction à l'architecture de la machine à votre collège local. Pendant ce temps, sérialiser correctement. Ne jamais traiter les structures comme des tableaux de char.
Quand vous allez à envoyer, il suffit d'utiliser:
(char*)&CustomPacket
à convertir. Fonctionne pour moi.
Vous pouvez convertir un unsigned char tableau.
Sauf si vous avez très convaincre les mesures montrant que chaque octet est précieux, ne pas faire cette. Utiliser un lisible protocole ASCII comme SMTPNNTPou l'un des nombreux autres beaux les protocoles de l'Internet codifiée par l'IETF.
Si vous devez vraiment avoir un format binaire, c'est toujours pas à l'abri juste à pousser les octets dans une struct, parce que l'ordre des octets, des tailles de base, ou l'alignement des contraintes peuvent différer d'hôte à hôte. Vous devez concevoir votre fil protcol bien et de tailles définies à l'utilisation d'un bien défini l'ordre des octets. Pour votre mise en œuvre, soit utiliser des macros comme
ntohl(3)
ou de l'utilisation déplacement de masquage et de mettre octets dans votre flux. Quoi que vous fassiez, assurez-vous que votre code produit les mêmes résultats sur big-endian et little-endian hôtes.