First, let me share a little syntax comparison I found interesting:
In C++ code:
int i = 0;
int number = 5;
while(i < 5){
i++;
}
cout << "We have looped " << i << " times." << endl;
In masm32 code:
mov ax,0
mov ecx,5
L1:
inc ax
loop L1
In both languages, we've looped 5 times, and got there by keeping track of how many times we have looped. It's interesting, though, how in C++ the loop counter counts forward and compares, while in assembly the program counts backwards instead, while watching for when the ECX register decrements to zero.
However, those rules don't help me understand the example from the review questions in my book:
What will be the final value of EAX in the following code:
mov eax,0
mov ecx,10 ;outer loop counter
L1:
mov eax,3
mov ecx,5 ;inner loop counter
L2:
add eax,5
loop L2 ;repeat inner loop
loop L1 ;repeat outer loop
The answer in the back of the book says:
"This is a trick! The program does not stop, because the first loop instruction decrements to zero, and the second loop instruction decrements ECX to FFFFFFFFh, causing the outer loop to repeat."
WTF?! :icon_eek: I'm sorry, but none of that makes any sense to me. NONE of it. Any help?
first, - there is an icon above the Reply window that looks like this: #
it adds "code" tags
so - write the code, select it (highlight) - then click the icon
it will look like this, keeping the columns lined up
code
morecode
next, i would say that's a terrible example to publish for someone learning assembler - lol
you wouldn't see it in any book i wrote or recommended
mov eax,0
mov ecx,10 ;outer loop counter
L1:
mov eax,3
mov ecx,5 ;inner loop counter
L2:
add eax,5
loop L2 ;repeat inner loop
loop L1 ;repeat outer loop
but, if you really want to understand it, then just examine the inner loop, alone
mov eax,3
mov ecx,5 ;inner loop counter
L2:
add eax,5
loop L2 ;repeat inner loop
now it makes sense
if you want to add the outer loop, one way might be to add PUSH and POP
(i am guessing that's where the book is leading you to)
mov eax,0
mov ecx,10 ;outer loop counter
L1:
push ecx
mov eax,3
mov ecx,5 ;inner loop counter
L2:
add eax,5
loop L2 ;repeat inner loop
pop ecx
loop L1 ;repeat outer loop
whether or not you push EAX will change the result
but, the loop will function either way
i might add.....
one big advantage of assembler...
you can keep a handful of variables in register, resulting in faster code
with high-level languages, those variables are often kept in memory (on the stack, sometimes)
dedndave is of course right except for one thing: the book's example is not so bad, because it demonstrates a trap to watch out for.
Consider the inner loop:
L2:
mov ecx, 5
; do any loop processing here, as long as you don't change the value of ecx
loop L2
; here ecx will always be 0
- the "loop" instruction decrements ecx; it it's nonzero it branches back to L, if zero, it falls thru. Thus it will always be zero when you fall thru.
Now, put another loop around that one:
L1:
; doesn't matter what ecx is set to here since it will be changed to 5 below
L2:
mov ecx, 5
; do any loop processing here, without changing value of ecx
loop L2
; here ecx will always be 0
loop L1:
- When it hits "loop L1:", ecx will always be 0. So that instruction will first subtract 1, making ecx = -1; then compare it to zero. Of course, -1 (i.e., 0FFFFFFFFh) is NOT zero so it will always branch back to L1: an infinite loop. That's not what you wanted!
- The book is demonstrating this mistake, so you won't do it in your code
Quote from: dedndave on September 09, 2015, 12:25:41 PM
i might add.....
one big advantage of assembler...
you can keep a handful of variables in register, resulting in faster code
with high-level languages, those variables are often kept in memory (on the stack, sometimes)
Of course with C++, you're also given the option to declare variables on the heap, which is much faster than storing their values in conventional memory.
:biggrin:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
comment * -----------------------------------------------------
Build this template with
"CONSOLE ASSEMBLE AND LINK"
----------------------------------------------------- *
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
mov ecx, 5 ; count required
xor eax, eax ; the value to increment
lbl:
add eax, 1 ; increment the value
sub ecx, 1 ; decrement the loop counter
jnz lbl ; loop again if ECX != 0
print str$(eax),13,10
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
Quote from: dedndave on September 09, 2015, 12:22:41 PM
but, if you really want to understand it, then just examine the inner loop, alone
mov eax,3
mov ecx,5 ;inner loop counter
L2:
add eax,5
loop L2 ;repeat inner loop
So first you initialize eax with 3 and then tell the ecx register you want the loop to iterate 5 times.
Next you add 5 to the eax register, which, on the first iteration, would make the new value in eax 8?
If I'm correct so far, in the end, the final value in eax would be 28.
Am I correct?
Quote from: dedndave on September 09, 2015, 12:22:41 PM
now it makes sense
if you want to add the outer loop, one way might be to add PUSH and POP
(i am guessing that's where the book is leading you to)
mov eax,0
mov ecx,10 ;outer loop counter
L1:
push ecx
mov eax,3
mov ecx,5 ;inner loop counter
L2:
add eax,5
loop L2 ;repeat inner loop
pop ecx
loop L1 ;repeat outer loop
You're so accurate it's scary. Yep, that's the exact solution the book gives. :t
Quote
You're so accurate it's scary. Yep, that's the exact solution the book gives. :t
He probably wrote the book. lol
Quote from: RedSkeleton007 on September 09, 2015, 01:30:58 PM
Of course with C++, you're also given the option to declare variables on the heap, which is much faster than storing their values in conventional memory.
Depends where the heap is... but it's not in the registers AFAIK... so we must be looking at memory, most likely the stack (which is a memory block) ;)
I've never tried to control the cache levels.. not sure if you can control it, or control it predictably as the overhead might negate the advantage... maybe someone knows, or has tried this.
Quote from: RedSkeleton007 on September 09, 2015, 01:30:58 PMdeclare variables on the heap, which is much faster than storing their values in conventional memory.
There are all the necessary tools in The Laboratory to support your (false) claim with evidence :P
> declare variables on the heap, which is much faster than storing their values in conventional memory
This is claptrap, memory is memory is memory, data is either stored in memory or stored in a register, their ain't nothing else.
i suspect accessing stack variables via [EBP+/-xx] is improved over some other methods (xx being signed byte)
but, depending on cache status, direct addressing is probably a little faster
although, it does produce larger code - in some cases, that may negate the advantage
generally speaking, values in register are going to be the fastest
it does bring to light a big difference of writing in assembler vs a high level compiler
that is - you control which variables are stored where
tedious perhaps, but can have advantages
So am I correct about the inner loop based on what I said here
http://masm32.com/board/index.php?topic=4577.msg49122#msg49122 (http://masm32.com/board/index.php?topic=4577.msg49122#msg49122)
yes, 3 + 5*5 = 28 :t
:biggrin:
Dave,
I would like to see that formula bracketed as it is ambiguous as it is.
(3+5)*5 = 40
3+(5*5) = 28
*** WARNING: Nit-pick alert ***
it's not really ambiguous, due to operator precedence (* binds b4 +)
Quote from: hutch-- on September 10, 2015, 08:39:38 AM
...as it is ambiguous as it is.
Not really.
Actually that is one of the few things I remember from school. Multiplication always comes first. :lol:
Don't ask what else follows in what order, now THAT I simply do not remember.
3+5+5+5+5+5 :P
Interesting that of all programmers, only assembly language programmers could be unsure of mathematical operator precedence. All others languages allow an expression like "6/2 + 5*5" so the programmer must know how it evaluates; but for assembler the knowledge is irrelevant
altho, come to think of it, I have seen competent C programmers who don't really know precedence rules; they always put parentheses, just to make sure
Quote from: hutch-- on September 10, 2015, 08:39:38 AM
:biggrin:
Dave,
I would like to see that formula bracketed as it is ambiguous as it is.
(3+5)*5 = 40
3+(5*5) = 28
Not necessary. Hasn't anybody here ever heard of the old mnemonic "
Please
Excuse
My
Dear
Aunt
Sally"?
Parentheses
Exponents
Multiplication
Division
Addition
Subtraction
As long as you use PEMDAS, you can't go wrong ;)
Quote from: RedSkeleton007 on September 10, 2015, 01:46:00 PM
Hasn't anybody here ever heard of the old mnemonic "
Quote
Parentheses
Exponents
Multiplication
Division
Addition
Subtraction
As long as you use PEMDAS, you can't go wrong ;)
Um, thats's an ACRONYM that you just used. :lol:
Haven't heard of it, but I'm OldSkool.
Quote from: RedSkeleton007 on September 10, 2015, 01:46:00 PM
As long as you use PEMDAS, you can't go wrong ;)
As long as you use parentheses to make any non-obvious precedence obvious, you can't go wrong.
i think it's a "phonetic" - what do i know
as for the parens, i sometimes use them, even when they are not needed
it helps, when reading the code later, to understand how an expression was derived
WindowWidth-(NumberColumns-6)
ok - had to google it - it's a mnemonic
a word we ought to know - lol
Quote from: dedndave on September 10, 2015, 03:23:02 PM
ok - had to google it - it's a mnemonic
a word we ought to know - lol
Damn, I must be having another memory leak. :lol:
Happens more and more lately. I'm getting to be an old fart.
Hi,
Back in the "good old days", I heard it as Pretty Pink Roses My
Dear Aunt Sally. For Parentheses, Powers, Roots, Multiplication,
Division, Addition, and Subtraction.
Cheers,
Steve N.
In case there's still confusion,
"Please Excuse My Dear Aunt Sally" is a mnemonic
PEMDAS is an acronym
Personally I never heard of it (since I never taught math below college level). Anyway, it's wrong. Addition does NOT bind b4 subtraction, rather, they have the same precedence, and are evaluated left to right. Thus
9 - 4 + 3 = 8, NOT 9 - (4+3) which would give 7
Same with multiplication and division, So
9 / 4 * 3 = 6.75 NOT 9 / (4*3) = .75
Must admit I'm not sure what Hebrew mathematicians (speakers of languages that are written right to left) do, I suppose they follow the left-to-right convention of English. Also, must admit I've seen people treat mult as binding b4 division. But the "official" convention is as I say, so PEMDAS should be something like
P
E
M, D
A, S
BTW this relates to a comment I made elsewhere. Traditionally academic ability is said to have two varities, math and verbal (of course reality is infinitely more complex but this is a good first cut). And, traditionally (40 years ago) programming was thought to need math more than verbal. In fact, I think verbal ability is more important for programming (believe it or not) because the key skill is very related to parsing a sentence. That's essentially what we're doing with "PEMDAS" - while the actual arithmetic operations are of course done by the machine, not the programmer
:biggrin:
Now you know why I bracket formulas. Came from studying logic using Tarski's notation from a text book by Donald Kalish and Richard Montague. Bracteting is extremely UNambiguous. :P
>9 - 4 + 3 = 8, NOT 9 - (4+3) which would give 7
Using brackets would change the sign of 3
9 - 4 + 3 = 8
9 - (4 - 3) = 8
@sinsi,
of course you're right, but I suspect you missed my point. The PEMDAS rule was stated incorrectly. It said that addition "takes precedence" (or, "binds before") subtraction. That means you could always put brackets around the two numbers being added, to get (in this case)
9 - (4 + 3)
but that's wrong. Addition does NOT bind b4 subtraction, rather they evaluate left to right. Therefore you're right, if you want to use brackets here u must change the sign.
I hope that's clear but am afraid it's not.
@hutch,
Whenever I have to do basic arithmetic, like 9-4+3, I always consult my well-thumbed copy of Principia Mathematica to make sure I'm doing it right. Doesn't everybody? Can't imagine how people added numbers together before Russell, Tarski etc showed us how :P