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...
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.