begin process at 2012 05 27 14:52:42
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Astuces

 > CONVERSION BINAIRE/DECIMAL/HEXADECIMAL - TRES SIMPLE [DJGPP]

CONVERSION BINAIRE/DECIMAL/HEXADECIMAL - TRES SIMPLE [DJGPP]


 Information sur la source

Note :
6,2 / 10 - par 5 personnes
6,20 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Astuces Niveau :Débutant Date de création :19/10/2002 Date de mise à jour :19/10/2002 13:14:01 Vu / téléchargé :55 174 / 979

Auteur : gorgonzola

Ecrire un message privé
Site perso
Commentaire sur cette source (5)
Ajouter un commentaire et/ou une note

 Description

Cliquez pour voir la capture en taille normale
Tout le monde fait des fonctions complique pour comparer des nombres avec des puissances de deux mais il y a une maniere beaucoup plus simple avec les unions

Source

  • #include <stdio.h> /* pour printf */
  • #include <conio.h> /* pour getch */
  • /*
  • Nouveau type de char, il prend exactement la meme place en
  • memoire qu'un vrai char.
  • C'est une union donc chaque membre de la structure occupera
  • la meme place en memoire.
  • */
  • typedef union NEWCHAR
  • {
  • unsigned char dec; /* decimal */
  • struct
  • {
  • bool bit8:1; /* binaire, le :1 */
  • bool bit7:1; /* signifie que la */
  • bool bit6:1; /* variable n'intervient */
  • bool bit5:1; /* que sur un seul bit */
  • bool bit4:1; /* de la structure */
  • bool bit3:1;
  • bool bit2:1;
  • bool bit1:1;
  • };
  • struct
  • {
  • unsigned int hexa2:4; /* hexadecimal, le :4 */
  • unsigned int hexa1:4; /* pour seulement 4 bits */
  • };
  • };
  • /*
  • les sous-structure de NEWCHAR ne porte pas de nom, ça permet d'acceder
  • a leurs variables comme ci elles appartenaient directement a NEWCHAR
  • et que en meme temps toutes leurs variables n'en valent qu'une seule
  • dans l'union
  • */
  • int main()
  • {
  • NEWCHAR octet;
  • octet.dec=173; /* octet = 173 */
  • /* binaire */
  • printf("binaire : %d%d%d%d%d%d%d%d\n",octet.bit1,octet.bit2,octet.bit3,octet.bit4,octet.bit5,octet.bit6,octet.bit7,octet.bit8);
  • /* hexadecimal */
  • printf("hexadecimal : ");
  • if (octet.hexa1>9) printf("%c",octet.hexa1+55);
  • else printf("%d",octet.hexa1);
  • if (octet.hexa2>9) printf("%c\n",octet.hexa2+55);
  • else printf("%d\n",octet.hexa2);
  • /* decimal */
  • printf("decimal : %d",octet.dec);
  • getch();
  • return 0;
  • }
#include			<stdio.h>	/* pour printf */
#include			<conio.h>	/* pour getch  */

/*
   Nouveau type de char, il prend exactement la meme place en 
   memoire qu'un vrai char.
   C'est une union donc chaque membre de la structure occupera
   la meme place en memoire.
*/

typedef union NEWCHAR		
{
	unsigned char	dec;	/* decimal */
	struct
	{
		bool	bit8:1;	/* binaire, le :1        */
		bool	bit7:1; /* signifie que la       */ 
		bool	bit6:1; /* variable n'intervient */
		bool	bit5:1; /* que sur un seul bit   */
		bool	bit4:1; /* de la structure       */
		bool	bit3:1;
		bool	bit2:1;
		bool	bit1:1;
	};
	struct			
	{
		unsigned int	hexa2:4;	/* hexadecimal, le :4    */
		unsigned int	hexa1:4;        /* pour seulement 4 bits */
	};
};

/*
   les sous-structure de NEWCHAR ne porte pas de nom, ça permet d'acceder
   a leurs variables comme ci elles appartenaient directement a NEWCHAR
   et que en meme temps toutes leurs variables n'en valent qu'une seule
   dans l'union
*/

int				main()
{
	NEWCHAR			octet;

	octet.dec=173;		/* octet = 173 */

	/* binaire */
	printf("binaire :     %d%d%d%d%d%d%d%d\n",octet.bit1,octet.bit2,octet.bit3,octet.bit4,octet.bit5,octet.bit6,octet.bit7,octet.bit8);

	/* hexadecimal */
	printf("hexadecimal : ");
	if (octet.hexa1>9) printf("%c",octet.hexa1+55);
	else printf("%d",octet.hexa1);
	if (octet.hexa2>9) printf("%c\n",octet.hexa2+55);
	else printf("%d\n",octet.hexa2);

	/* decimal */
	printf("decimal :     %d",octet.dec);

	getch();

	return 0;
}

 Conclusion

voila c'est vraiment pas complique

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Sources du même auteur

Source avec Zip Source avec une capture RESOLUTION D'EQUATIONS (JUSQU'AU 3EME DEGRE) + CLASSE POUR M...
Source avec Zip DESSINER A LA MAIN UNE STRUCTURE FRACTALE [DJGPP] [VGA 13H]
Source avec Zip JEU DE LA VIE EN MODE VGA 11H [DJGPP]
Source avec Zip Source avec une capture GENERATEUR DE FRACTAL PERSONNALISE [VESA] [DJGPP]
Source avec Zip MODE VESA HAUTE RESOLUTION [DJGPP]

 Sources de la même categorie

Source avec Zip SCHEDULER RR FIFO par yvesB87
Source avec Zip ALGORITHMES RÉCURSIFS VS ALGORITHMES ITÉRATIFS par yvesB87
Source avec Zip Source avec une capture C++ FORMAT D'IMAGE AVEC QT par pop70
Source avec une capture EXEMPLE DE POINTEURS DE FONCTION par pop70
Source avec Zip Source avec une capture [C++] CLASS REGISTER par Miwik

Commentaires et avis

Commentaire de BeLZeL le 10/10/2004 15:28:46

J'avais déjà entendu parlé de cette technique. Le problème, c'est que apparemment, ca ne compile pas "directement" sous DevCpp. J'ai remplacé les BOOL par UNSIGNED CHAR car chez moi, il arrive à trouver des BOOL négatifs (allez comprendre pourquoi...). En mettant des UNSIGNED CHAR partout, plus de pb de conversion de type.

Voilà l'équivalent de l'union pour DevCpp :
[code]
#include <windows.h> //<-------------
#include <stdio.h>   /* pour printf */
#include <conio.h>   /* pour getch   */

typedef union U_NEWCHAR //<-------------
{
    unsigned char   dec;    
    struct
    {
        unsigned char    bit8:1; //<-------------
        unsigned char    bit7:1; //<-------------
        unsigned char    bit6:1; //<-------------
        unsigned char    bit5:1; //<-------------
        unsigned char    bit4:1; //<-------------
        unsigned char    bit3:1; //<-------------
        unsigned char    bit2:1; //<-------------
        unsigned char    bit1:1; //<-------------
    };
    struct
    {
        unsigned char    hexa2:4;  
        unsigned char    hexa1:4;  
    };
} NEWCHAR; //<-------------
[/code]

Voiloi voilou :)

Commentaire de deck_bsd le 30/07/2005 15:54:19

Bonjour,


Voila, j'ai des petits problèmes de compréhension de ce code, je le comprend, ce que je comprend pas c'est comment ce fait til que ça fasse la conversion (je c c un peu bizar ma phrase lol).

J'espère que vous saurez combler mes lacunes.

++all

Commentaire de BeLZeL le 31/07/2005 11:00:14

Tout est dans la création, un peu spéciale, de la structure, avec "typedef UNION".
La structure permet d'utiliser les 3 unions en même temps, mais une seule initialisation est nécessaire.
C'est-à-dire que quand on fait octet.dec=<nombre>, on remplit également octet.bitX et octet.hexaX.
dec, bitX et hexaX prennent tous exactement 8 bits en mémoire.
Voilà pourquoi ca marche.

Commentaire de deck_bsd le 01/08/2005 08:38:50

Je te remercie pour ton explication, je comprend mieu mainteant :D

Commentaire de Pigeo le 22/01/2007 16:54:57


Il y a un certain nombre d'autres intérets à utiliser cette astuce, et un certain nombre d'applications autres que la conversion binaire/decimal/hexadecimal... Vu que personne n'en a parlé jusque ici, j'ai pas pu m'empecher de faire ce post :-) Pour ceux qui ont toujours des petits problemes de comprehension du fonctionnement de ce code, rendez-vous à la fin de mon post.

Un autre intérêt de l'astuce citée par gorgonzola, et non des moindres, c'est la vitesse d'execution du code... Si vous comparez la vitesse d'execution de ce code source par rapport aux méthode classique des puissances de deux (ou des décallage de bits et masques binaires), vous verrez que ce code source est plus rapide :-) (suivant si vous activez les optimisations ou non, et suivant le niveau d'optimisation l'ecart sera plus ou moins grand mais en tout cas ce code est toujours plus rapide que la méthode classique).

Deux autres applications de cette astuce :

- pour convertir un entier long (32 bits) en entier court (16 bits), ou un char (8 bits) en entier long (32 bits), etc. Avec le code suivant :
[code]
typedef union NEWINT32
{
unsigned int32 entier; /* 32bits */
struct
{
unsigned char  octet1 : 8;
unsigned char  octet2 : 8;
unsigned char  octet3 : 8;
unsigned char  octet4 : 8;
};
struct
{
unsigned int16 mot1 : 16;
unsigned int16 mot2 : 16;    
};
};
[/code]


- pour convertir un entier (16, 32, ou 64 bits) de Little Endian à Big Endian, et vice versa... Sur processeur Intel, dans un entier, les octets de poids faibles sont stockés en premier, suivi des entiers de poids fort. Sur Motorola, c'est l'inverse. (a moins que ca ne soit le contraire, je ne me souviens jamais !) Du coup quand vous envoyez un paquet IP d'un mac à un PC et vice versa... il faut bien que l'adresse IP (32 bits) soient stockée d'une certain manière dans le paquet IP... Et du coup votre ordi fait des conversions Big endian / little endian  en permanence (les fonctions qui font ca c'est ntohs, ntohl, htonl, htons... voir http://www.codeproject.com/cpp/endianness.asp par exemple.)

Maintenant il y en a qui se demandent peut etre pourquoi ce code est plus optimisé que la méthode classique ? Et bien, lorsque ce code source est compilé en langage machine, en fait le compilateur se contente de faire le strict minimum pour accéder au bits demandés. Tandis qu'avec la méthode "classique" des puissances de deux ou des décallage de bits et masques binaires, le compilateur n'est pas en mesure de comprendre "sémantiquement" ce qu'on est en train de faire, et traduit notre code "tel quel" en langage machine  (un peu comme une traduction mot à mot dans Babelfish, quoi, vous imaginez le résultat...) du coup on se retrouve avec un code assembleur super compliqué tout ca pour accéder à un bit d'un octet !

En règle général, quand vous avez le choix entre un code tres court, avec tres peu d'instructions, et un autre beaucoup plus gros, avec plus d'instructions, qui font tous les deux la meme chose, celui qui est plus petit a toutes les chances d'etre mieux traduit en langage machine par le compilateur, surtout s'il s'agit d'un mauvais compilateur (qui ne fait pas l'effort d'essayer de "comprendre" le code source et qui ne possède pas de "vision globale" du code source).

D'ailleurs, meme si cette méthode n'etait pas plus claire et plus lisible que les méthodes classiques, et meme si elle n'etait pas plus optimisée que les méthodes classiques... elle serait quand meme mieux ! :-) Pourquoi ? Parce que si demain vous voulez optimiser un compilateur ou bien faire votre propre compilateur pour un nouveau type de processeur, et que ce processeur possède une instruction en langage machine qui permet de tester un bit donné dans un octet, vous pourrez tres facilement faire en sorte que quand le compilateur voit "ma_variable.bit3" dans le code source, c'est traduit en une seule instruction machine, tandis qu'avec les méthodes classiques, vous pourrez toujours vous accrocher pour faire en sorte que le compilateur reconnaisse qu'il s'agit de l'extraction d'un bit dans un octet et qu'il arrive à optimiser tout ca pour le traduire en une seule instruction machine, au lieu de faire bêtement des décallages, des masques, patin couffin, tout ca pour arriver au meme resultat au final. L'optimisation des compilateurs c'est un sujet tres délicat et il est toujours possible de faire mieux dans ce domaine là. Sur la plupart des compilateurs du marché, meme en compilant avec les options d'optimisations au niveau max, les optimisations réalisées sont vraiment très en-dessous de ce qu'il serait theoriquement possible de faire. Autrement dit, ce code là a toute les chances de tourner de plus en plus vite lorsque les compilateurs seront plus optimisés ou que les processeurs évolueront. Les méthodes classiques, en revanche, ont toutes les chances de ne pas "se faire optimiser" aussi vite, donc l'écart de performance entre les deux ne pourra que devenir de plus en plus important :-)

Maintenant, ce qui est dommage... C'est que partiquement PERSONNE n'utilise cette astuce !!! Et ca c'est vraiment VRAIMENT dommage. J'ai bossé dans plusieurs grandes boites d'informatique, et je peux vous dire que tout le monte utilise la méthode classique avec les décallages et les masques de bits. Moi meme j'avoue que par le passé, avant de connaitre cette astuce, j'ai fait la meme boulette que tous ces autres informaticiens. Et c'est vraiment couillon, parce que c'est juste par ignorance, autrement il n'y a aucune raison de ne pas utiliser cette astuce. Au contraire, elle est beaucoup plus lisible et simple à écrire, plus consise ! D'ailleurs sur le site que j'ai mentionné plus haut, http://www.codeproject.com/cpp/endianness.asp, ils donnent en code source un truc barbare du style (((nLongNumber&0x000000FF)<<24)+((nLongNumber&0x0000FF00)<<8)+ ((nLongNumber&0x00FF0000)>>8)+((nLongNumber&0xFF000000)>>24))... BERK !!! ca me donne la nausée, j'ai meme pas envie d'essayer de déchiffrer ces hiéroglyphes !!! lol

Enfin bon, que voulez-vous... aujourd'hui tout le monde s'en fou royalement de faire du code optimisé, et le nombre de ligne de codes d'un programme est un argument marketing... Si votre programme fait plusieurs millions de lignes de codes, on va vous admirer, alors que le type d'a coté qui a fait le meme programme en plus rapide mais avec 4 fois moins de lignes de code il va passer completement inappercu. Que voulez-vous ! Pas étonnant apres qu'on se retrouve avec un répertoire Windows qui pèse plusieurs Gigas, et que rien que pour afficher la liste des disques dur dans l'explorateur mon Pentium 4 dernier cri rame sa mère qu'il en peut plus... ca met plusieurs secondes ! Et encore j'ai un giga de RAM. C'est devenu indispensable aujourd'hui, avec tous ces programmes obèses mal programmés qui sont devenus boulimiques de RAM. Bref, et là je sens les linuxiens qui rigolent dans leur coin en se disant que Windows c'est de la merde et que Linux c'est merveilleux c'est génial c'est carrément top... ouais, bin, ils feraient mieux de jeter un coup d'oeuil au code source... Hem, à l'epoque ou je bidouillais pas mal dans le kernel de linux et tout ca, bin je peut vous dire que les conversions binaires/hexa/decimal elles etaient aussi faites avec la methode classique et non pas avec cette astuce ! :-) Comme quoi, je vous dit, PERSONNE n'utilise cette astuce, et c'est vraiment regrettable :-(

en fait le gros "# typedef union NEWCHAR" c'est juste une structure qui superpose dans le meme espace mémoire (de 8 bits) à la fois un char, 8 booleens, et 2 entiers sur 4 bits... Comme ils occupent le meme espace mémoire, quand on écrit quelque chose dans un des booleens, ca modifie aussi le char et les 2 hexa. C'est un peu comme si c'etait des pointeurs qui pointent vers la meme case mémoire, sauf que c'est pas des pointeurs (C'est le compilateur qui se démerde pour faire en sorte que ces variables soient stockées dans la meme "case" mémoire de 8 bits). Ce qui est bien c'est que la déclaration de cette union, on peut la mettre dans un fichier include, et ensuite on peut l'utiliser à plein d'endroits, jusque en écrivant une ligne, "NEWCHAR octet;" et accéder bit par bit ou 4bits par 4bits, sans se prendre la tete avec des lignes de code compliquées :-)

Voila voila, je crois que j'ai fait le tour de ce que j'avais à dire. Bon, sinon en ce qui concerne la conversion de big endian en little endian, il y a une autre méthode qui est encore plus rapide (et que personne n'utilise non plus), mais bon je vais pas m'attarder là dessus, mon post est deja beaucoup trop long comme ca !

 Ajouter un commentaire




Nos sponsors


Sondage...

CalendriCode

Mai 2012
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Consulter la suite du CalendriCode

Photothèque

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,764 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales