home comics writing pictures archive about

2018-12-22 - In IL: Print the Alphabet (break, continue)

In IL

One final aspect of looping that we haven't looked at yet are the use of break and continue statements. These statements allow you more control over how loops progress. break statements stop the loop and move to the next statement after the loop while continue statements stop the current loop and moves execution onto the next iteration. We are going to start by looking at the same for loop we had before but with some break and continue statements added.

Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CsBreakContinue
{
class Program
{
static void Main(string[] args)
{
for (char ch = 'A'; ch <= 'Z'; ch++)
{
if (ch % 2 == 0)
continue;
if (ch >= 'K')
break;
Console.Write(ch);
}
Console.WriteLine();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

This loop skips over all "even" letters and stops the loop when we hit the letter k. Now let's look at the compiled code.

Main
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 37 (0x25)
.maxstack 2
.locals init ([0] char ch)
IL_0000: ldc.i4.s 65
IL_0002: stloc.0
IL_0003: br.s IL_001a
IL_0005: ldloc.0
IL_0006: ldc.i4.2
IL_0007: rem
IL_0008: brfalse.s IL_0015
IL_000a: ldloc.0
IL_000b: ldc.i4.s 75
IL_000d: bge.s IL_001f
IL_000f: ldloc.0
IL_0010: call void [mscorlib]System.Console::Write(char)
IL_0015: ldloc.0
IL_0016: ldc.i4.1
IL_0017: add
IL_0018: conv.u2
IL_0019: stloc.0
IL_001a: ldloc.0
IL_001b: ldc.i4.s 90
IL_001d: ble.s IL_0005
IL_001f: call void [mscorlib]System.Console::WriteLine()
IL_0024: ret
} // end of method Program::Main
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

This looks very close to our previous for loop but with extra code to check for even letters and the letter k. In the first case we branch to the incrementing part of the loop and continue on from there. In the second case we branch to the first statement after the loop. Now we are going to make those same modifications to the while loop we had before.

Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CsBreakContinue2
{
class Program
{
static void Main(string[] args)
{
char ch = 'A';
while (ch <= 'Z')
{
if (ch % 2 == 0)
continue;
if (ch >= 'K')
break;
Console.Write(ch);
ch++;
}
Console.WriteLine();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

Now if we compile this we expect to see the same code as our for loop since the original fore loop and while loop compile to the same code.

Main
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 37 (0x25)
.maxstack 2
.locals init ([0] char ch)
IL_0000: ldc.i4.s 65
IL_0002: stloc.0
IL_0003: br.s IL_001a
IL_0005: ldloc.0
IL_0006: ldc.i4.2
IL_0007: rem
IL_0008: brfalse.s IL_001a
IL_000a: ldloc.0
IL_000b: ldc.i4.s 75
IL_000d: bge.s IL_001f
IL_000f: ldloc.0
IL_0010: call void [mscorlib]System.Console::Write(char)
IL_0015: ldloc.0
IL_0016: ldc.i4.1
IL_0017: add
IL_0018: conv.u2
IL_0019: stloc.0
IL_001a: ldloc.0
IL_001b: ldc.i4.s 90
IL_001d: ble.s IL_0005
IL_001f: call void [mscorlib]System.Console::WriteLine()
IL_0024: ret
} // end of method Program::Main
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

Now you might say the compiled code is identical to the compiled code for the for loop and you would almost be right except for one important distinction. The continue part branches to the loop conditional check and not the increment part like the for loop does. This causes the program to go into an infinite loop and never exit.

As I mentioned when we looked at for loops the main difference between for loops and while loops is what is and isn't a part of the loop from the compiler's perspective. In the for loop case the incrementing is part of the loop so the compiler makes sure that's ran even if we use a continue. In the while case we are responsible for the incrementing so the compiler ignored it and goes straight to the conditional check. This is something to keep in mind when you are using break or continue.

Next time we're going to look at some array instructions.

Comments: