Post-test loops
prerequisite
Unlike a pre-test loop, where the condition is checked before the loop body runs, a post-test loop runs the loop body first and checks the condition afterward. This means that even if the condition is false from the start, the loop body still runs once. This lesson builds one in assembly and then runs it beside a pre-test loop so the difference shows.
What a post-test loop is
A post-test loop is a type of loop in which the loop condition is checked after each pass through the body, including the first. The body therefore runs at least once, even when the condition is false from the start.
In C, a post-test loop is written as a do-while loop, which checks its condition after each pass through the loop body. The following C code starts i at 6, already past the limit of 5:
#include <stdio.h>int main() { // do-while loop implementation // i starts past the limit, yet the body runs once printf("Post-test loop implementation\n"); int i = 6; do { printf("%d\n", i); i++; } while (i <= 5); printf("Loop finished\n"); return 0;}The loop above prints 6 once. The test i <= 5 is false the first time it is checked, but by then the body has already run. The same loop written as a while loop, which tests first, prints nothing between its two lines. When i starts at 1, the two kinds of loop print the same numbers, 1 to 5: they only differ when the condition is false on the very first check.
note
The term post-conditional loop refers to a post-test loop. The two terms are interchangeable.
The logic behind it
The underlying logic is:
PRINT "Post-test loop implementation"DECLARE i AS INTEGERi = 6PRINT ii = i + 1IF i <= 5 THEN JUMP BACK TO PRINT iPRINT "Loop finished"The difference from a pre-test loop is when the condition is checked: here the body runs first.
The pre-test version opens with a branch to the loop condition. Remove that branch and execution falls straight into the body.
The assembly implementation
The C code and pseudocode above can be written in assembly as follows:
ldr x0, =fmt_head bl printf mov i_r, 6 // i = 6: the test is false from the start // no branch to the test, so the body runs firstloopbody: ldr x0, =fmt_i mov w1, i_r // pass i to printf bl printf add i_r, i_r, 1 // i = i + 1loopcond: cmp i_r, 5 b.le loopbody // go again while i <= 5 ldr x0, =fmt_done bl printfThe instructions match the pre-test version: set the loop variable, run the body, add one, check the condition. Only the opening b loopcond is gone, so nothing is tested until the body has run once. With i at 6, the body prints 6, i becomes 7, the check 7 <= 5 fails, and the loop ends after one pass.
The whole program
The following code is the complete post-test loop program, including the data section, the prologue, and the epilogue. It prints Post-test loop implementation, then 6, then Loop finished. Change the 6 to 1 and it prints the numbers 1 to 5, exactly as the pre-test loop does.
note
main changes w19 without saving it first, a shortcut these lessons take only in main. A subroutine you write yourself must save any of x19 to x28 it changes and restore them before it returns, as Subroutines: saved registers, pointers, and big arguments shows.
Side by side
The program below runs both kinds of loop from the same start value, one after the other, and labels each line of output. Both loops count up while the counter is at most LIMIT. With START set to 6, the pre-test loop's line stays empty and the post-test loop's line shows its one extra pass:
pre-test:post-test: 6Set START to 1 and both lines read 1 2 3 4 5. Set it to 5 and both read 5. Only a start past the limit tells the two loops apart.
pitfall
Pick a post-test loop only when the body must run at least once, such as showing a menu before the first choice is read. For counting, a pre-test loop is the safer choice: a do-while loop that should have run zero times still runs once, and that extra pass is easy to miss.
Check yourself
- A program must show a menu once and keep showing it while the user picks 9. Which kind of loop fits?
- In the side-by-side program, what does each line print when
STARTis 4? - What one change turns the program in Pre-test loops into the post-test loop on this page, apart from the start value?
- A
do-whileloop startsiat 10 and repeats whilei < 3. How many times does its body run?
answers
show answers
- A post-test loop, because the menu must appear at least once.
pre-test: 4 5andpost-test: 4 5.- Deleting
b loopcond, the jump to the test before the first pass. - Once: the body runs, and then the first check,
i < 3, fails.
Practice
- Fix the loop bound: a loop that stops one step too early.
- Reverse the digits: peel digits off a number until none are left.
- Guess the number: read guesses until one hits. The body runs before the test, so a post-test loop fits.
- The multiplication table: one loop inside another.
- Fizzbuzz, by hand: a counting loop with an else-if chain inside it.
- Basic quiz: loops, then core: pre-test against post-test, loops inside loops,
break, and calls inside a loop body. The core quiz'scbnzquestion comes with the next lesson. - Predict: loops (challenge): trace counting loops, a post-test loop, a loop inside a loop, and an unsigned test.