MSNA de l'Assemblée convertir les données d'entrée à l'entier?
Ok, donc je suis assez nouveau à l'assemblée, enfait, je suis très nouveau à l'assemblée. J'ai écrit un bout de code qui veut simplement prendre numériques d'entrée de l'utilisateur, de le multiplier par 10, et avoir le résultat est exprimé à l'utilisateur par le biais de programmes de statut de sortie (en tapant echo $? dans le terminal)
Le problème est qu'il n'est pas de donner le nombre exact, 4x10 a montré que 144. Alors j'ai pensé que l'entrée serait probablement aussi un personnage, plutôt que d'un entier. Ma question est, comment puis-je convertir la saisie de caractères pour un nombre entier de sorte qu'il peut être utilisé dans des calculs arithmétiques?
Ce serait génial si quelqu'un pouvait répondre en gardant à l'esprit que je suis un débutant 🙂
Aussi, comment puis-je convertir dit entier retour à un personnage?
section .data
section .bss
input resb 4
section .text
global _start
_start:
mov eax, 3
mov ebx, 0
mov ecx, input
mov edx, 4
int 0x80
mov ebx, 10
imul ebx, ecx
mov eax, 1
int 0x80
OriginalL'auteur user2862492 | 2013-10-11
Vous devez vous connecter pour publier un commentaire.
Voici un couple de fonctions pour la conversion de chaînes en nombres entiers, et vice-versa:
Et c'est de cette façon que vous souhaitez utiliser:
Noter que je ne fais pas beaucoup de contrôle d'erreur dans ces routines (comme vérifier si il y a des caractères en dehors de la plage
'0' - '9'
). Ni les routines de manipuler des nombres signés. Donc, si vous avez besoin de ces choses que vous aurez à ajouter vous-même.loop
instruction! Aussi, 2 LEA instructions sont nettement mieux queimul
+add
:lea ebx, [4*ebx + ebx]
(ebx*=5) /lea ebx, [eax + 2*ebx]
. Ou avez-vous été l'optimisation du code-taille?sub al,'0'
enregistre 1 octet sursub eax,'0'
, mais provoque une partielle-registre de décrochage sur Nehalem/Core2 et encore pire sur PIII. (Bien sur Sandybridge; c'est un RMW de AL, afin de ne pas renommer l'partielle reg séparément de EAX.)Et si vous n'avez pas besoin de vérifier pour être valide d'un chiffre décimal comme une condition de boucle, vous pouvez lea ebx, [eax + 2*ebx - '0'] " pour éviter la
sub
entièrement, mais ce qui permettrait d'augmenter la LEA de latence de 3 sur les Processeurs Intel.OriginalL'auteur Michael
La base algorith pour chaîne->chiffre est:
total = total*10 + digit
, à partir de la MSD. Si la gauche de la plus /Plus Importante /premier chiffre (de mémoire, et dans l'ordre de lecture) est multiplié par 10 N fois, où N est le nombre total de chiffres après.Cette façon de faire est généralement plus efficace que de multiplier chaque chiffre par la droite de la puissance de 10 avant d'ajouter. Qui aurait besoin de 2 multiplie; on de cultiver une puissance de 10, et un autre pour l'appliquer aux chiffres. (Ou une table look-up avec croissant des puissances de 10).
Bien sûr, pour plus d'efficacité, vous pouvez utiliser SSSE3
pmaddubsw
et SSE2pmaddwd
de multiplier les chiffres par leur place-valeur en parallèle: voir Comment mettre en œuvre atoi à l'aide SIMD?. Ce n'est probablement pas une victoire quand les nombres sont généralement courte, si. Un scalaire boucle est efficace quand la plupart des numéros sont à seulement quelques chiffres.Ajoutant à @Michael réponse, il peut être utile d'avoir l'int->fonction de chaîne arrêter à la première non-chiffres, au lieu d'une longueur fixe. Cela permettra de repérer les problèmes comme votre chaîne, y compris un retour à la ligne à partir de quand l'utilisateur appuie sur le retour, ainsi que de ne pas se
12xy34
dans un très grand nombre. (La traiter comme12
, comme C estatoi
function). Le caractère de fin peut également être appelé à disparaître0
dans un C implicite chaîne de longueur.J'ai aussi fait quelques améliorations:
Ne pas utiliser la lenteur de
boucle
enseignement sauf si vous êtes l'optimisation de code de taille. Juste oublier qu'il existe et utiliserdec
/jnz
dans le cas où le compte à rebours à zéro est toujours ce que vous voulez faire, au lieu de comparer un pointeur ou quelque chose d'autre.2 LEA instructions sont nettement mieux que
imul
+add
: la faible latence.accumuler le résultat dans EAX où nous voulons revenir de toute façon. (Si vous inline cela au lieu de l'appeler, quel que soit le registre, vous voulez le résultat.)
J'ai changé les registres il s'ensuit donc le x86-64 V ABI (Premier arg à RDI, de retour dans EAX).
Portage à 32 bits: Cela ne dépend pas de 64 bits à tous; qu'il peut être porté à 32 bits en utilisant simplement les registres 32 bits. (c'est à dire remplacer
rdi
avecedi
,rax
avececx
, etrax
aveceax
). Méfiez-vous de l'appel C-convention de différences entre les versions 32 et 64 bits, par exemple, l'EDI est préservée et les arguments sont généralement passés sur la pile. Mais si votre interlocuteur est l'asm, vous pouvez passer d'un arg en EDI.Cela empêche la conversion sur le premier non-chiffre. Souvent, ce sera l'0 octet qui met fin à un implicite chaîne de longueur, mais vous pourriez vérifier après la boucle qui
ecx == -'0'
si vous voulez détecter se terminant sur un autre chiffre. Si votre entrée est explicite-chaîne de longueur, vous aurez besoin d'utiliser un compteur de boucle, au lieu de vérifier un terminator (comme @Michael réponse), parce que le prochain octet dans la mémoire peut être un autre chiffre. Ou il pourrait être dans un unmapped page.Prise de la première itération de spécial et de le manipuler avant de sauter dans la partie principale de la boucle est appelée boucle peeling. Éplucher la première itération, nous permet d'optimiser spécialement, parce que nous savons total=0 donc il n'y a pas besoin de multiplier tout par 10. C'est comme commencer avec
sum = array[0]; i=1
au lieu desum=0, i=0;
.Pour obtenir belle boucle de la structure (avec la branche conditionnelle en bas), j'ai utilisé l'astuce de sauter dans le milieu de la boucle pour la première itération. N'en est pas de même de prendre un supplément de
jmp
parce que j'étais déjà ramification dans le pelées première itération.La manière la plus simple de résoudre le problème de la sortie de la boucle sur un chiffre serait d'avoir un
jcc
dans le corps de la boucle, comme unif() break;
déclaration en C avant latotal = total*10 + digit
. Mais alors j'aurais besoin d'unejmp
et ont 2 total de la branche d'instructions dans la boucle, ce qui signifie plus de frais généraux.Si je n'ai pas besoin de la
sub ecx, '0'
résultat de la condition de la boucle, j'aurais pu utiliserlea eax, [rax*2 + rcx - '0']
qu'elle fasse partie de la LEA ainsi. Mais qui aurait fait de la LEA de latence de 3 cycles au lieu de 1, sur Sandybridge-famille de Processeurs. (3-composante LEA vs 2 ou moins.) Les deux Lea former une boucle transportées à la chaîne de dépendances sureax
(total
), donc (surtout pour les grands nombres) il ne serait pas utile sur Intel. Sur les Processeurs oùbase + scaled-index
est pas plus rapide quebase + scaled-index + disp8
(Bulldozer-famille /Ryzen), alors bien sûr, si vous avez une longueur explicite en tant que votre condition de boucle et ne veulent pas les chiffres.J'ai utilisé movzx à charger avec zéro extension en premier lieu, au lieu de le faire après la conversion de l'chiffres du code ASCII en entier. (Il doit être fait à un certain point à ajouter dans le 32 bits EAX). Souvent le code qui manipule les chiffres ASCII utilise octet de l'opérande de taille, comme
mov cl, [rdi]
. Mais ce serait une fausse dépendance sur l'ancienne valeur de RCX sur la plupart des Processeurs.sub al,'0'
enregistre 1 octet sursub eax,'0'
, mais provoque une partielle-registre de décrochage sur Nehalem/Core2 et encore pire sur PIII. Fine sur toutes les autres familles de CPU, même Sandybridge: c'est un RMW de AL, afin de ne pas renommer l'partielle reg séparément de EAX. Maiscmp al, 9
ne cause pas un problème, parce que la lecture d'un octet de registre est toujours beau. Il enregistre un octet (un encodage sans ModRM octet), j'ai donc utilisé que dans le haut de la fonction.Pour une meilleure optimisation des trucs, voir http://agner.org/optmize, et d'autres liens dans le x86 balise wiki.
La balise wiki a aussi débutant liens, y compris une section FAQ avec des liens vers entier->fonctions de chaîne, et d'autres questions de débutant.
Connexes: Comment puis-je imprimer un nombre entier au Niveau de l'Assemblée de la Programmation sans printf de la bibliothèque c? est l'inverse de cette question, entier -> base10string.
OriginalL'auteur Peter Cordes