exemple lorsque je fais :
char test1,test2 ;
test1 = 0xaa;
test2 = 0xaa;
short result = ((test1<<8)+test2);
cout << hex << "result = " << result << endl;
Ceci me retourne :
result = a9aa
Est-ce que quelqu'un peut me dire ou est l'erreur ?
char test1,test2 ;
test1 = 0xaa;
test2 = 0xaa;
short result = ((test1<<8)+test2);
cout << hex << "result = " << result << endl;
# au hasard ...
Posté par NeoX . Évalué à 1.
ou tu fais un decalage d'un char sur lui meme avant de concatener tes 2 chars en un short.
et bizarrement ton <<8 devient au final un soustraction puisque 0xaa devient 0xa9
[^] # Re: au hasard ...
Posté par Wo0chY . Évalué à 1.
Je suis ralenti c'est vendredi
PS. si je test la meme chose avec, par exemple test1=test2= 0x77 le résultat est bien 7777
[^] # Re: au hasard ...
Posté par NeoX . Évalué à 1.
test1=0xaa
test1 - 1 = 0xa9
et on dirait que c'est ce que fait ton
test1 decalée de 8 => 0xa900
mais cela aurait du faire pareil avec 0x77 => 0x7677
et les effets de bords ne devrait se faire sentir que vers 0xFF
[^] # Re: au hasard ...
Posté par Obsidian . Évalué à 5.
Un char fait huit bits de large, donc :
1) (test1 << 8) fait huit décalages sur un registre de huit bits, ce qui revient en principe à tous les faire sortir et donc ramener le registre à zéro. Le C++ fait donc soit un transtypage implicite à priori, soit une optimisation spécifique à l'architecture et au compilateur, comme stocker des char sur des long et faire de l'alignement sur des adresses multiples de 4. Mais bon, passons.
2) Ce qui est surtout intéressant, c'est le bit de signe. 0x77, ça fait 119 en décimal et c'est un nombre positif. Par contre, sur huit bits signés, 0xaa, ça ne pas 170 mais -86 ! Comme tu utilises "+", tu obtiens une soustraction.
Utilise "unsigned char" plutôt que char pour commencer.
Ensuite, tu peux également utiliser une tableau "unsigned char tableau [2];" et déposer tes valeurs directement dedans avec tableau[0] et et tableau[1]. Au moins tu es sûr que tes valeurs sont concaténées en mémoire, et dans le bon ordre. Sachant cela, tu n'as plus qu'à les lire comme s'il s'agissait d'un short, en utilisant un transtypage (cast) :
short result = *(short *)tableau;
Ca peut être déroutant pour un coder de haut niveau, c'est la manière la plus naturelle de travailler pour le microprocesseur, qui ne fera aucune conversion dans le code final.
Enfin, tu essaies d'être propre et portable, tu oublies la dernière proposition et tu fais man ntohs.
Si tu veux que je développe, tu n'hésites pas.
[^] # Re: au hasard ...
Posté par Obsidian . Évalué à 2.
unsigned char test1, test2;
unsigned short result = (((unsigned short)test1) <<8) | test2;
Note le " | " à la place du place " + ".
Je suis presque sûr que le C++ a transformé le "AA" en short signé devenu "FFAA", ce qui explique le -1 sur l'octet de poids fort, donc le "A9AA".
Si l'on garde le code original, mais que l'on remplace + par | et que l'on arrive à FFAA, c'est que c'est ça.
[^] # Re: au hasard ...
Posté par neologix . Évalué à 1.
En C, c'est faux. Le standard te dit qu'il fait au moins 8 bits de large (pour stocker jusqu'à 2^7-1). Mais il peut faire plus.
Mauvaise idée...
Rien ne te dit comment les données sont alignées en mémoire. Pour la plupart des processeurs, les données doivent être alignées à une adresse spécifique (multiple de 2, ou 4 par exemple pour un long). Lorsque tu fais un cast comme ça, tu peux lui demander d'aller chercher un short à une adresse qu'il n'aime pas, et provoquer une erreur de segmentation.
C'est comme lorsque tu essaies de dépaqueter une structure:
cf: http://c-faq.com/strangeprob/ptralign.html
Les types ont une (bonne) raison d'exister: il ne faut pas utiliser un cast pour "prétendre que telle donnée est de tel type", ou pour demander au compilo de la fermer...
[^] # Re: au hasard ...
Posté par Obsidian . Évalué à 3.
Sauf qu'ici, il y a de bonnes chances pour qu'il fasse effectivement huit bits, et que son format provoque des effets de bord. Chaque chose en son temps ...
Si tu avais lu mon commentaire jusqu'au bout, et celui qui suit avec, tu serais tombé sur :
Enfin, tu essaies d'être propre et portable, tu oublies la dernière proposition et tu fais man ntohs.
Sinon
unsigned char test1, test2;
unsigned short result = (((unsigned short)test1) <<8) | test2;
[^] # Re: au hasard ...
Posté par alf . Évalué à 1.
Arg !
J'avais pas fait gaffe à première lecture, mais quand même...
short result = 0;
unsigned char *p = (unsigned char*) &result;
p[0] = 0xaa;
p[1] = 0xaa;
Ce code n'a aucun problème d'alignement (ce qui est correctement aligné pour un truc quelconque qui n'est pas un champ de bits sera toujours correctement aligné pour un unsigned char). Par contre, la valeur de result reste dépendante de CHAR_BITS.
(il y a plantage éventuel suivant sizeof(short) qui peut être égal à 1, mais un if ou une bête boucle peut suffire à gérer correctement tous les cas)
# Comportement non défini en C
Posté par Yvan Joffre . Évalué à 2.
En général, avec gcc, cette expression vaut simplement :
a << (b % (sizeof(a) * 8))
En général, un char fait 8 bits. Donc 'test1 << 8' vaut simplement test1, avec le type 'char'. Ton expression vaut donc la somme de deux char sur 8 bits.
Tu peux écrire si tu veux (((short)test1) << 8)) + test2
[^] # Re: Comportement non défini en C
Posté par Wo0chY . Évalué à 1.
Merci quand même
[^] # Re: Comportement non défini en C
Posté par Jerome Herman . Évalué à 0.
Rapidement en char signé (par défaut) si tu fais
char test1 = 0xaa;
Ton char va en fait valoir bit à bit en mémoire 0xffaa.
Avec unsigned char ca marche. Maintenant quand on veut concaténer des bits il vaut nettement mieux utiliser les outils & et | logiques bit à bit.
[^] # Re: Comportement non défini en C
Posté par Obsidian . Évalué à 3.
[^] # Re: Comportement non défini en C
Posté par alf . Évalué à 1.
Plus grand ou égal. D'où un problème (en C du moins).
Mais il y a autre chose. Si le type char est signé (en C, c'est possible, et même courant. En C++, à voir, mais je suppose que c'est pareil.), et si CHAR_BIT vaut 8 (ce qui est garanti par POSIX, si je ne m'abuse), alors la valeur maximale pour un char est 127.
Or 0xaa == 170.
D'où débordement, sur un type signé, et donc comportement indéfini (en C toujours).
En utilisant unsigned char à la place, il n'y a plus débordement à ce niveau, et a vaut bien 170.
Ensuite, j'ai un doute et la flemme de resortir la norme, mais il me semble que les opérandes de << subissent la promotion entière. Donc la valeur de a est convertie en int avant qu'on calcule le a << 8. Pasunsigned int.
Et 170 << 8, hors débordement, ça fait 170 * 2^8 = 43520 (et donc 43690 avec le + b). Si ton int est sur plus de 16 bits, ça passe. Puis tu stockes le tout dans un short. Si short fait aussi plus de 16 bits, ça passe.
Si short et/ou int est signé et fait 16 bits, alors je rappelle que la valeur max d'un type signé sur 16 bits est 32767... i.e. il y aura débordement (et donc comportement indéfini pour ceux qui suivent).
D'où, sauf erreur de ma part, une solution :
unsigned char a = 0xaa;
unsigned char b = 0xaa;
unsigned short s1 = a << 8 + b;
/* si jamais je me suis trompé sur la promotion entière */
unsigned short s2 = (((unsigned int) a) << 8) + b;
Vu tous les comportements indéfinis rencontrés en chemin, je ne prends pas la peine de chercher pourquoi tu as 0xa9aa plutôt que -1, 42 ou SIGSEV...
[^] # Re: Comportement non défini en C
Posté par Yvan Joffre . Évalué à 1.
Bon, c'est quand même très souvent le cas.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.