2013-08-21 1 views
0

J'écris un programme pour afficher l'heure et la date actuelles pendant 10 secondes. Je suis dirigé que je peux utiliser UNIQUEMENT smallwin.inc pour cela. J'ai écrit un programme qui fonctionne en utilisant Irvine32.inc, mais quand je passe à Smallwin, je devais écrire quelques procédures pour la sortie des nombres. Quand j'ai ajouté ces derniers, un comportement TRÈS ÉTRANGE a commencé à se produire! J'utilise l'appel "dec repTime" et il diminuera de 2 au lieu de 1! J'ai essayé "sub repTime, 1" et il fait toujours la même chose! J'ai même déplacé repTime à eax, puis soustrait 1, puis déplacé eax à repTime, il soustrait toujours 2!Comportement étrange dans MASM: directive "dec" provoque la soustraction par 2

Le programme que j'ai écrit est supposé fonctionner pendant 10 secondes. En raison du problème de soustraction 2, il fonctionne pendant 4 secondes à la place! Qu'est-ce qui ne va pas?!?

Voici mon code:

; this code demonstrates the usage of Windows API functions to display 
; current date and time. It provides a running digital clock that updates 
; itself for 10 seconds. The output is displayed starting with cursor position 
; (5,5) and uses yellow foreground and blue background. 

INCLUDE smallwin.inc 

.data 
buffer DB 256 DUP(?) 
prompt BYTE "Today is: "     ; strings used to format the output 
slash  BYTE '/' 
colon  BYTE ':' 
space  BYTE "  Time: " 
newLine WORD 0D0Ah       
repTime DWORD 10       ; display time for 10 seconds 
cursPos COORD <5,5>      ; cursor coordinates 

.data? 
outHandle DWORD ?       ; storage for console output handle 
sysTimeNow SYSTEMTIME <>      ; storage for system time structure 
sysTimeFuture SYSTEMTIME <> 

.code 

WriteChar PROC 

pushfd 
pushad 
mov buffer,al 
INVOKE WriteConsole, outHandle, OFFSET buffer, 1, 0, 0 

popad 
popfd 
ret 
WriteChar ENDP 

outInt PROC USES eax ebx ecx edx, 
number: SDWORD    ; method parameter 
mov ebx, 10    ; divisor for the radix system 
xor ecx, ecx    ; digits counter 
cmp number, 0    ; is number >= 0? 
jge go      ; yes - proceed 
neg number     ; negate the number 
mov al, '-' 
INVOKE WriteChar 

go: 
mov eax, number 
puDigit: 
xor edx, edx 
div ebx     ; get one digit 
push edx     ; save it for further processing 
inc ecx     ; update the digits counter 
cmp eax, 0     ; end of processing 
jne puDigit 

printIT: 
pop eax      ; get a digit from stack 
or al, 30h     ; ASCII conversion 
INVOKE WriteChar   ; print it 
loop printIT 

ret 
outInt ENDP 

format2 PROC 
LOCAL zero:BYTE 

mov zero, '0' 
cmp ax, 10        ; number < 10 ? 
jge L 
push eax        ; YES - output preceeding 0 
INVOKE WriteConsole, outHandle, ADDR zero, 1, 0, 0 
pop eax 
L: INVOKE outInt, eax       ; output the number itself 

ret 
format2 ENDP 


main PROC 
INVOKE GetStdHandle, STD_OUTPUT_HANDLE 
mov outHandle, eax      ; get console handle for output 

INVOKE SetConsoleTextAttribute, outHandle, 30 ; setup colors 
INVOKE GetLocalTime, ADDR sysTimeFuture 

;set Future Time to Dec 25, 2013 
mov sysTimeFuture.wDay, 25 
mov sysTimeFuture.wMonth, 12 
mov sysTimeFuture.wYear, 2013 
mov sysTimeFuture.wHour, 0 
mov sysTimeFuture.wMinute, 0 
mov sysTimeFuture.wSecond, 0 


startLabel: 
INVOKE SetConsoleCursorPosition, outHandle, cursPos 

INVOKE GetLocalTime, ADDR sysTimeNow  ; retrieve current date/time 

INVOKE WriteConsole, outHandle, ADDR prompt, 
SIZEOF prompt, 0, 0     ; output prompt 

mov eax, 0 
mov ax, sysTimeNow.wDay     ; day of the month 
call format2 
INVOKE WriteConsole, outHandle, ADDR slash, 1, 0, 0 ; output '/' 

mov ax, sysTimeNow.wMonth     ; month number 
call format2 
INVOKE WriteConsole, outHandle, ADDR slash, 1, 0, 0 ; output '/' 

mov ax, sysTimeNow.wYear     ; print out the year 
INVOKE outInt, ax 
INVOKE WriteConsole, outHandle, ADDR space, SIZEOF space, 0, 0 

mov ax, sysTimeNow.wHour     ; output hours 
call format2 
INVOKE WriteConsole, outHandle, ADDR colon, 1, 0, 0 ; output ':' 

mov ax, sysTimeNow.wMinute     ; output minutes 
call format2 
INVOKE WriteConsole, outHandle, ADDR colon, 1, 0, 0 ; output ':' 

mov ax, sysTimeNow.wSecond     ; output seconds 
call format2 

INVOKE Sleep, 1000      ; wait for 1 second 
dec repTime        ; update the stop watch counter 
jnz startLabel 

INVOKE SetConsoleTextAttribute, outHandle, 15 ; reset the colors 
INVOKE WriteConsole, outHandle, ADDR newLine, 2, 0, 0 ; start new line 
INVOKE ExitProcess, 0 
main ENDP 

END main 
+0

Comment avez-vous observé cela? En passant par le code dans un débogueur ..? – Michael

+0

Non, si vous exécutez le programme, il ne fonctionnera que pendant 4 secondes. J'ai fait "INVOKE outInt, repTime" après l'instruction dec, et vous pouvez voir chaque seconde que l'horloge monte d'une seconde et la valeur de repTime diminue de 2. – Drifter64

+0

En plaçant une invocation outInt avant et après le décrément montre que le En fait, la diminution ne diminue que de 1, mais d'une manière ou d'une autre, avant que l'instruction soit à nouveau atteinte, elle est décrémentée EXTRA. Si vous produisez, décrémentez, puis produisez dans une boucle, le comportement attendu devrait être une sortie comme "5,4 4,3 3,2 2,1", où les espaces séparent chaque boucle, cependant, la sortie est en fait "5, 4 3,2 1,0 "ce qui signifie que la décrémentation fonctionne correctement, mais en quelque sorte cette adresse de mémoire est en train d'être foiré ailleurs! – Drifter64

Répondre

0

Regardez le prototype outint:

outInt PROTO number:SDWORD 

Le paramètre attendu est un S SIGNÉ DWORD - SDWORD ou il pourrait être DWORD, Peu importe, regardez ce que vous passez en paramètre:

mov  ax, sysTimeNow.wYear     ; print out the year 
INVOKE outInt, ax 

Vous passez un registre de taille WORD en tant que paramètre, et vous utilisez eax dans la procédure.

Modifier les deux lignes ci-dessus à:

ou:

xor  eax, eax 
mov  ax, sysTimeNow.wYear     ; print out the year 
INVOKE outInt, eax 

qui va "zéro" la moitié supérieure de eax et le faire fonctionner. Ou, ce que vous pourriez faire, c'est faire la procédure s'attendre à un paramètre de taille WORD puisque c'est ce que vous passez, et utilisez ax au lieu de eax dans le proc.

+0

Je pense que je comprends maintenant. Il est prévu de regarder plus d'espace dans la mémoire que je le donne ....et il arrive probablement que la prochaine zone dans la mémoire se trouve être cette variable repTime, donc elle manipule un peu ses valeurs. Merci beaucoup! – Drifter64

+0

J'ai décidé d'étendre le déplacement à zéro et d'utiliser le registre eax en passant. :) – Drifter64

Questions connexes