This loop is used when the number of iterations is not known beforehand. The while loop is a pretest loop, and its execution depends on the initial condition. Its general syntax can be presented as follows :
while (condition) <statements>
The loop exits if the condition is false. Since the condition is checked at the beginning of each iteration, it may happen that the body of the loop is not executed even once.
In C++, a while loop looks like this:
while (condition) { <statements> }
The following fragment of code demonstrates the use of the while loop. Suppose you have an array of ten integers and want to find the number of elements that precede the first zero element (if there is any). A fragment of the program should return the number of elements that precede the first zero element or a zero if such an element is not found. This code could be used to search for and extract null- terminated strings. This task is easily implemented with a for loop, but here we will do this with a while loop.
The following variables will be used:
x1 ”an integer array
Ix1 ”the current array index
sx1 ”the array size
Counter ”the counter of elements
This fragment of code will be executed as follows:
After initialization of the variables, the program checks the element of the X1 array for being not equal to zero at the beginning of each iteration in the while loop. If the element is equal to zero, the loop intermediately interrupts.
If the condition is true, i.e., the array element is not equal to zero, the loop body is executed. The Counter and the IX1 index are incremented. If the last element of the array is encountered , the loop exits (the if statement).
In any case, the Counter contains the number of elements that precede the first zero element or a zero if such an element is not found.
The Visual C++ code for this task is shown in Listing 4.4.
... int X1[10] = {i2, 90, 6 , 30, 2 2 , 10, 2 2 , 89, 0, 47}; int Counter = 0; int IX1 = 0; int SX1 = sizeof (X1) / 4; while (X1[IX1] != 0) { Counter++; if (IX1 == SX1) break; IX1++; }; if (Counter == SX1+1) Counter = 0; ...
At first glance, the implementation of this task in the assembler (Listing 4.5) would seem more complicated than in the previous examples.
.686 .model flat, stdcall .data X1 DD 2, 2 3, 5, 9, 1, 0, 9, 3 SX1 DD $ X1 Counter DD 0 .code start: push EBX mov ECX, 0 mov EBX, offset X1 mov EDX, DWORD PTR SX1 shr EDX, 2 mov ESI, EDX AGAIN: mov EAX, DWORD PTR [EBX] cmp EAX, 0 je RUNOUT inc ECX dec EDX jz RUNOUT add EBX, 4 jmp AGAIN RUNOUT: cmp ECX, ESI jne SET_CNT xor ECX, ECX SET_CNT: mov DWORD PTR Counter, ECX pop EBX ... end start
A few important notes should be made. The first one relates to the use of registers. When working with external programs and modules in high-level languages, it is recommended that you save the EBX , EBP , ESI , and EDI registers by pushing them on the stack. With regard to the other registers ( EAX , ECX , and EDX ), you can use them as you like.
The second note relates to work with arrays and strings in the assembler. To access such data in Windows, 32-bit variables that store the addresses of the arrays and strings are always used. To access the elements of the X1 array, you can use the EBX register by putting the address of the first array element to it:
mov EBX, offset X1
To work with an array, you should know its size. It can be stored in the EDX register:
mov EDX, DWORD PTR SX1
The counter of non-zero elements is stored in the ECX register. Since each element of the array is four bytes long (a double word), the following command is used to access the next element:
add EBX, 4
This example includes two high-level constructions: a while loop and an if conditional statement. The while loop is implemented with three commands:
mov EAX, DWORD PTR [EBX] cmp EAX, 0 je RUNOUT,
and the if statement is implemented with the following commands:
cmp ECX, EDX je RUNOUT
If no zero element is found, zero is written to the counter according to the condition of the task:
cmp ECX, EDX jne SET_CNT xor ECX, ECX
We provide such a detailed analysis of the assembly version of the program so that you understand that there is no unique solution for the task of optimization of logical structures in high-level languages! In many cases, a building block of such an optimization is the following pair of assembly commands:
cmp operand1, operand2 Jcond label
In principle, the assembler allows you to implement any logical expressions and branches, no matter how complicated they are. The only limitation is your imagination and experience.
A while loop can be implemented in the assembler by using commands of string primitives. These commands are widely used for processing arrays and strings in loops and often simplify the algorithm of a task. A variant of implementing a while loop with the scasd command is shown in Listing 4.6.
.686 .model flat, stdcall .data X1 DD 2, 2 3, 5, 9, 1, 0, 9, 3 SX1 DD $X1 IX1 DD 1 Counter DD 0 .code start: mov EDI, offset X1 xor ECX, ECX mov EDX, DWORD PTR SX1 shr EDX, 2 cld xor EAX, EAX next: scasd je ex inc ECX dec EDX jz ex jmp next ex: cmp ECX, 10 jne write_cnt mov Counter, 0 jmp quit write_cnt: mov Counter, ECX quit: . . . end start