Conversion nombre -> chaine de caractère (hexa,dec,oct,bin) (16bits,mode réel, tasm)

Contenu du snippet

Ce code est 16bits mode réel.

Il permet de convertir un nombre mis dans AX vers une chaine de caractères dans DS:SI dans plusieurs bases :
-> Décimale
-> Hexadécimale
-> Binaire
-> Octale

Le code a été dévellopé avec TASM.

Source / Exemple :


MODEL SMALL
STACK 100h

DATA SEGMENT
  Chaine DB 25 DUP ('$')
  Prompt DB 'Conversion de $'
  ChHexa DB 'en hexa :0x$'
  ChDec  DB 'en decimal :$'
  ChBin  DB 'en binaire :0b$'
  ChOct  DB 'en octal :0o$'
  ChNeg  DB 'en negatif :$'
  CRLF   DB 13,10,'$'
DATA ENDS

CODE SEGMENT
  ASSUME CS:CODE,DS:DATA

TerminalChar EQU '$'

;inverse une chaine
;==================
;DS:SI : adresse du début de la chaine
;DS:DI : adresse de fin de la chaine (avant le caractère de terminaison de chaine)
InverseChaine PROC
  ;on inverse la chaine puisque l'on a calculé la représentation à l'envers (méthode des divisions successives)
  boucleInv:
    ;on échange [DI] <-> [SI]
    MOV AL,byte ptr [DI]
	MOV AH,byte ptr [SI]
	MOV byte ptr [SI],AL
	MOV byte ptr [DI],AH
	;octets suivants
	DEC DI
	INC SI
	;tant que l'on n'a pas tout inversé (SI < DI)
	CMP SI,DI
	JL boucleInv
  RET
InverseChaine ENDP

;convertit un nombre en sa représentation décimale (chaine)
;==========================================================
;DS:SI : adresse où stocker la chaine
;AX : nombre à convertir
;CX=1 : nombre signé, CX=0 : non signé
ChaineDec PROC
  ;sauvegarde des registres
  PUSH DX
  PUSH DI
  PUSH CX
  PUSH SI
  PUSH AX

  ;si le nombre est non signé
  CMP CX,0
  ;on passe à la conversion
  JE PasSigne
  ;sinon, on calcule la valeur absolue
  ;si AX est >= 0
  CMP AX,0
  JGE PasSigne
  ;valeur absolue de AX
  NEG AX
  ;on ajoute le signe
  MOV byte ptr [SI],'-'
  ;on passe au caractère suivant
  INC SI

  PasSigne:
  ;sauvegarde de l'offset de départ de la chaine
  MOV DI,SI

  ;mot de poids fort dans le dividende
  XOR DX,DX

  ;tant qu'il y a des chiffres à ajouter
  boucleDec:
    ;CX=AX pour le calcule du reste de division
    MOV CX,AX

    ;division par 10 : algo de Terje Mathisen
	;========================================
    MOV DX,0CCCDh
    ;on divise AX par 10 : résultat dans DX
    MUL DX
	SHR DX,3
	;========================================

	;on sauvegarde de résultat dans AX
	MOV AX,DX

	;on calcule le reste de la division de CX(=AX avant division)
	SHL DX,1  ;DX = quotient * 2
	SUB CX,DX ;CX = divende - quotient * 2
	SHL DX,2  ;DX = quotient * 2 * 4 = quotient * 8
	SUB CX,DX ;CX = dividende - quotient * 2 - quotient * 8 = dividende - quotient * 10 = reste

    ;on ajoute '0'=48 pour convertir le chiffre en code ascii correspondant
	ADD CX,'0'

    ;on le copie dans la chaine
    MOV byte ptr [DI],CL

    ;on passe au caractère suivant
	INC DI
	;si le quotient est nul, on a fini la conversion
	CMP AX,0
	JA boucleDec

  ;on met un caractère de fin de chaine
  MOV byte ptr [DI],TerminalChar

  ;on se place avant le caractère de la fin de chaine
  DEC DI

  ;on inverse la chaine puisque l'on a calculé la représentation à l'envers (méthode des divisions successives)
  CALL InverseChaine

  ;récupération des registres
  POP AX
  POP SI
  POP CX
  POP DI
  POP DX
  RET
ChaineDec ENDP

;convertit un nombre en sa représentation héxadécimale (chaine)
;==============================================================
;DS:SI : adresse où stocker la chaine
;AX : nombre à convertir
;CX : nombre de digits
ChaineHex PROC
  ;sauvegarde des registres
  PUSH DX
  PUSH DI
  PUSH CX
  PUSH SI
  PUSH AX

  ;sauvegarde de l'offset de départ de la chaine
  MOV DI,SI

  ;tant qu'il y a des chiffres à ajouter
  boucleHexa:
    ;DX=AX pour le calcul du reste de AX / 16
    MOV DX,AX

    ;DX = reste de la division de AX par 16
	AND DX,15 ;DX = AX and 01111b = AX mod 16
    ;on divise AX par 16 = 2 ^ 4
    SHR AX,4

    ;le reste DX est-il entre 0 et 9
	CMP DX,9
	;si 9 < DX < 15
    JA LettreHexa
	;sinon, un chiffre
	ADD DX,'0'
	JMP MetChaine
    
	;on doit afficher une lettre Hexadécimale
	LettreHexa:
	ADD DX,'A'-10

    ;on met le caractère dans la chaine
    MetChaine:
    MOV byte ptr [DI],DL

    ;on passe au caractère suivant
	INC DI
	;un digit affiché en plus
	DEC CX
	;si le quotient est nul, on a fini la conversion
	CMP AX,0
	JA boucleHexa
  
  ;s'il n'y a plus de digit '0' à ajouter devant le nombre
  CMP CX,0
  ;on termine la chaine
  JLE FinChaineHexa
  
  ;sinon, on ajoute les '0' manquants
  boucle0Hexa:
    ;on met un "0"
    MOV byte ptr [DI],'0'
	;on passe au caractère suivant
	INC DI
	;tant que CX != 0
	LOOP boucle0Hexa

  ;on ajoute le caractère de fin de chaine
  FinChaineHexa:

  ;on met un caractère de fin de chaine
  MOV byte ptr [DI],TerminalChar

  ;on se place avant le caractère de la fin de chaine
  DEC DI

  ;on inverse la chaine puisque l'on a calculé la représentation à l'envers (méthode des divisions successives)
  CALL InverseChaine
  
  ;récupération des registres
  POP AX
  POP SI
  POP CX
  POP DI
  POP DX
  RET
ChaineHex ENDP

;convertit un nombre en sa représentation octale (chaine)
;==========================================================
;DS:SI : adresse où stocker la chaine
;AX : nombre à convertir
;CX : nombre de digits
ChaineOct PROC
  ;sauvegarde des registres
  PUSH DX
  PUSH DI
  PUSH CX
  PUSH SI
  PUSH AX

  ;sauvegarde de l'offset de départ de la chaine
  MOV DI,SI
  
  ;tant qu'il y a des chiffres à ajouter
  boucleOct:
    ;on divise AX par 8 : quotient dans AX, reste dans DX (DL)
	;calcul du reste
	MOV DL,AL ;DL=AL
	AND DL,07h ;DL = AL and 0111b = AL mod 8
	;division par 2 ^ 3 = division par 8
    SHR AX,3

    ;on ajoute '0'=48 pour convertir le chiffre en code ascii correspondant
	ADD DL,'0'

    ;on le copie dans la chaine
    MOV byte ptr [DI],DL

    ;on passe au caractère suivant
	INC DI
	;on a un digit de plus
	DEC CX
	;si le quotient est nul, on a fini la conversion
	CMP AX,0
	JA boucleOct

  ;s'il n'y a plus de digit '0' à ajouter devant le nombre
  CMP CX,0
  ;on termine la chaine
  JLE FinChaineOct

  ;sinon, on ajoute les '0' manquants
  boucle0Oct:
    ;on met un "0"
    MOV byte ptr [DI],'0'
	;on passe au caractère suivant
	INC DI
	;tant que CX != 0
	LOOP boucle0Oct

  ;on ajoute le caractère de fin de chaine
  FinChaineOct:

  ;on met un caractère de fin de chaine
  MOV byte ptr [DI],TerminalChar

  ;on se place avant le caractère de la fin de chaine
  DEC DI

  ;on inverse la chaine puisque l'on a calculé la représentation à l'envers (méthode des divisions successives)
  CALL InverseChaine
  
  ;récupération des registres
  POP AX
  POP SI
  POP CX
  POP DI
  POP DX
  RET
ChaineOct ENDP

;convertit un nombre en sa représentation décimale (chaine)
;==========================================================
;DS:SI : adresse où stocker la chaine
;AX : nombre à convertir
ChaineBin PROC
  ;sauvegarde des registres
  PUSH DX
  PUSH DI
  PUSH CX
  PUSH SI
  PUSH AX

  ;sauvegarde de l'offset de départ de la chaine
  MOV DI,SI

  ;tant qu'il y a des chiffres à ajouter
  boucleBin:
    ;on divise AX par 2 : quotient dans AX, reste dans DX (DL)
	;calcul du reste
	MOV DL,AL ;DL=AL
	AND DL,1  ;DL=AL and 2 = AL mod 2
	;division par 2
    SHR AX,1

    ;on ajoute '0'=48 pour convertir le chiffre en code ascii correspondant
	ADD DL,'0'

    ;on le copie dans la chaine
    MOV byte ptr [DI],DL

    ;on passe au caractère suivant
	INC DI
	;on a un digit de plus
	DEC CX
	;si le quotient est nul, on a fini la conversion
	CMP AX,0
	JA boucleBin

  ;s'il n'y a plus de digit '0' à ajouter devant le nombre
  CMP CX,0
  ;on termine la chaine
  JLE FinChaineBin

  ;sinon, on ajoute les '0' manquants
  boucle0Bin:
    ;on met un "0"
    MOV byte ptr [DI],'0'
	;on passe au caractère suivant
	INC DI
	;tant que CX != 0
	LOOP boucle0Bin

  ;on ajoute le caractère de fin de chaine
  FinChaineBin:

  ;on met un caractère de fin de chaine
  MOV byte ptr [DI],TerminalChar

  ;on se place avant le caractère de la fin de chaine
  DEC DI

  ;on inverse la chaine puisque l'on a calculé la représentation à l'envers (méthode des divisions successives)
  CALL InverseChaine
  
  ;récupération des registres
  POP AX
  POP SI
  POP CX
  POP DI
  POP DX
  RET
ChaineBin ENDP

;macro pour afficher une chaine à l'écran
Printf MACRO Chain
  PUSH AX
  MOV AH,09h    ;fonction 9 : "puts"
  LEA DX,Chain  ;DS:DX : adresse de la chaine à afficher
  INT 21h       ;interruption DOS
  POP AX
ENDM

;programme principal de test
  Deb:
  ;init de DS
  MOV AX,DATA
  MOV DS,AX

  ;DS:SI : adresse de la chaine résultat
  LEA SI,Chaine

  ;nombre à afficher
  MOV AX,0FFF9h

  ;================
  Printf Prompt

  ;affichage
  ;pas de signe
  MOV CX,0
  ;conversion
  CALL ChaineDec

  Printf Chaine
  Printf CRLF
  ;================
  Printf ChDec

  ;affichage
  ;pas de signe
  MOV CX,0
  ;conversion
  CALL ChaineDec

  Printf Chaine
  Printf CRLF
  ;================
  Printf ChHexa

  ;affichage
  ;4 digits
  MOV CX,4
  ;conversion
  CALL ChaineHex

  Printf Chaine
  Printf CRLF
  ;================
  Printf ChOct

  ;affichage
  ;conversion
  CALL ChaineOct

  Printf Chaine
  Printf CRLF
  ;================
  Printf ChBin

  ;affichage
  ;16 digits
  MOV CX,16
  ;conversion
  CALL ChaineBin

  Printf Chaine
  Printf CRLF
  ;================
  Printf ChNeg

  ;affichage
  NEG AX
  ;un signe
  MOV CX,1
  ;conversion
  CALL ChaineDec

  Printf Chaine
  Printf CRLF

  MOV AL,0
  MOV AH,04Ch
  INT 21h
CODE ENDS
END Deb

Conclusion :


N'hésitez pas à commenter et à noter...

Le code est commenté et optimisé (principalement DIV et MUL) dans les limites de mes connaissances...

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.