Difference between GOTO and DO WHILE
Are there any differences between the two C # snippets below?
do
{
Console.WriteLine(x.ToString());
++x;
}
while (x < 7);
and
label:
{
Console.WriteLine(x.ToString());
++x;
}
if (x < 7) goto label;
I'm trying to figure out why it's so bad. Thank.
EDIT: If I add parentheses, the fragments are pretty similar.
EDIT2: In Visual Studio, I clicked the Go to Disassemble button and got the following code:
do
{
00000037 nop
Console.WriteLine(x.ToString());
00000038 lea ecx,[ebp-40h]
0000003b call 63129C98
00000040 mov dword ptr [ebp-48h],eax
00000043 mov ecx,dword ptr [ebp-48h]
00000046 call 63148168
0000004b nop
++x;
0000004c inc dword ptr [ebp-40h]
}
0000004f nop
while (x < 7);
00000050 cmp dword ptr [ebp-40h],7
00000054 setl al
00000057 movzx eax,al
0000005a mov dword ptr [ebp-44h],eax
0000005d cmp dword ptr [ebp-44h],0
00000061 jne 00000037
and
label:
{
Console.WriteLine(x.ToString());
00000069 lea ecx,[ebp-40h]
0000006c call 63129C98
00000071 mov dword ptr [ebp-4Ch],eax
00000074 mov ecx,dword ptr [ebp-4Ch]
00000077 call 63148168
0000007c nop
++x;
0000007d inc dword ptr [ebp-40h]
}
00000080 nop
if (x < 7) goto label;
00000081 cmp dword ptr [ebp-40h],7
00000085 setge al
00000088 movzx eax,al
0000008b mov dword ptr [ebp-44h],eax
0000008e cmp dword ptr [ebp-44h],0
00000092 jne 00000097
00000094 nop
00000095 jmp 00000068
The difference is an unconditional jump.
source to share
No, I even think that it is while
implemented as in the back.
The bad goto
thing to use is that it encourages back and forth through your code (also known by the term "spaghetti code": it's a mess). This makes your code extremely difficult to read, debug, and analyze, and it introduces errors as you can't figure out what's going on.
The good thing with while
is that you can understand it and the compiler can understand it, so it can give you good warnings.
source to share
Let's take a look at IL:
.method private hidebysig
instance void While () cil managed
{
// Method begins at RVA 0x2050
// Code size 31 (0x1f)
.maxstack 2
.locals init (
[0] int32 x,
[1] bool CS$4$0000
)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
// loop start (head: IL_0003)
IL_0003: nop
IL_0004: ldloca.s x
IL_0006: call instance string [mscorlib]System.Int32::ToString()
IL_000b: call void [mscorlib]System.Console::WriteLine(string)
IL_0010: nop
IL_0011: ldloc.0
IL_0012: ldc.i4.1
IL_0013: add
IL_0014: stloc.0
IL_0015: nop
IL_0016: ldloc.0
IL_0017: ldc.i4.7
IL_0018: clt
IL_001a: stloc.1
IL_001b: ldloc.1
IL_001c: brtrue.s IL_0003
// end loop
IL_001e: ret
} // end of method Program::While
.method private hidebysig
instance void Goto () cil managed
{
// Method begins at RVA 0x207c
// Code size 34 (0x22)
.maxstack 2
.locals init (
[0] int32 x,
[1] bool CS$4$0000
)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
// loop start (head: IL_0003)
IL_0003: ldloca.s x
IL_0005: call instance string [mscorlib]System.Int32::ToString()
IL_000a: call void [mscorlib]System.Console::WriteLine(string)
IL_000f: nop
IL_0010: ldloc.0
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: ldc.i4.7
IL_0016: clt
IL_0018: ldc.i4.0
IL_0019: ceq
IL_001b: stloc.1
IL_001c: ldloc.1
IL_001d: brtrue.s IL_0021
IL_001f: br.s IL_0003
// end loop
IL_0021: ret
} // end of method Program::Goto
The ILSpy event marks goto as a loop. When decompiling it to C #, it even shows both loops as do while
.
But there is more! The while loop has a scope:
int x = 0;
do
{
string z = "TEST";
Console.WriteLine(x.ToString());
++x;
}
while (x < 7);
Console.WriteLine(z); // invalid!
but this is true:
int x = 0;
label:
string z = "TEST";
Console.WriteLine(x.ToString());
++x;
if (x < 7) goto label;
Console.WriteLine(z);
Should you use it? Not! Check out Patricks .
source to share