GOTO 与 DO WHILE 的区别
GOTO versus DO WHILE differences
以下 2 个 C# 代码片段在执行上有差异吗?
do
{
Console.WriteLine(x.ToString());
++x;
}
while (x < 7);
和
label:
{
Console.WriteLine(x.ToString());
++x;
}
if (x < 7) goto label;
我想弄清楚为什么 goto 这么糟糕。
谢谢
编辑:如果我添加方括号,片段非常相似。
EDIT2:在 Visual Studio 中,我点击了 Go to Disassembly,我得到了以下代码:
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
和
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
区别是无条件跳转
不,我什至认为 while
是像后面那样实现的。
使用 goto
的坏处在于它会鼓励您在代码中来回切换(也称为术语 'spaghetti code':一团糟)。它使您的代码极难阅读、调试和分析,并且会引入错误,因为您无法真正理解正在发生的事情。
while
的好处是,你 可以理解它,编译器也可以理解它,所以它可以给你很好的警告。
让我们看一下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[=10=]00
)
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[=10=]00
)
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
ILSpy 事件将 goto 标记为循环。将其反编译为 C# 时,它甚至将两个循环显示为 do while
.
但有不同! while 循环的范围是:
int x = 0;
do
{
string z = "TEST";
Console.WriteLine(x.ToString());
++x;
}
while (x < 7);
Console.WriteLine(z); // invalid!
但这是有效的:
int x = 0;
label:
string z = "TEST";
Console.WriteLine(x.ToString());
++x;
if (x < 7) goto label;
Console.WriteLine(z);
你应该使用它吗?不!请参阅 答案。
以下 2 个 C# 代码片段在执行上有差异吗?
do
{
Console.WriteLine(x.ToString());
++x;
}
while (x < 7);
和
label:
{
Console.WriteLine(x.ToString());
++x;
}
if (x < 7) goto label;
我想弄清楚为什么 goto 这么糟糕。 谢谢
编辑:如果我添加方括号,片段非常相似。
EDIT2:在 Visual Studio 中,我点击了 Go to Disassembly,我得到了以下代码:
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
和
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
区别是无条件跳转
不,我什至认为 while
是像后面那样实现的。
使用 goto
的坏处在于它会鼓励您在代码中来回切换(也称为术语 'spaghetti code':一团糟)。它使您的代码极难阅读、调试和分析,并且会引入错误,因为您无法真正理解正在发生的事情。
while
的好处是,你 可以理解它,编译器也可以理解它,所以它可以给你很好的警告。
让我们看一下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[=10=]00
)
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[=10=]00
)
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
ILSpy 事件将 goto 标记为循环。将其反编译为 C# 时,它甚至将两个循环显示为 do while
.
但有不同! while 循环的范围是:
int x = 0;
do
{
string z = "TEST";
Console.WriteLine(x.ToString());
++x;
}
while (x < 7);
Console.WriteLine(z); // invalid!
但这是有效的:
int x = 0;
label:
string z = "TEST";
Console.WriteLine(x.ToString());
++x;
if (x < 7) goto label;
Console.WriteLine(z);
你应该使用它吗?不!请参阅