我正在学习C#,遇到了这个问题:
static int F(int n)
{
if (n == 1)
return 1;
return 1;
}
这会生成预期的结果:
<Program>$.<<Main>$>g__F|0_0(Int32)
L0000: mov eax, 1
L0005: ret
正如你所看到的,编译器理解到这个if
语句是没有意义的,因此“删除”了它。
现在,让我们尝试添加更多的if
语句:
static int G(int n)
{
if (n == 1)
return 1;
if (n == 1)
return 1;
return 1;
}
现在,这将生成以下ASM
代码:
<Program>$.<<Main>$>g__G|0_1(Int32)
L0000: cmp ecx, 1 ; do we need this?
L0003: jne short L000b ; do we need this?
L0005: mov eax, 1
L000a: ret
L000b: mov eax, 1
L0010: ret
奇怪的是,当您添加“>=5”个分支时,它会再次理解它们是不需要的。
static int H(int n)
{
if (n == 1)
return 1;
if (n == 1)
return 1;
if (n == 1)
return 1;
if (n == 1)
return 1;
if (n == 1)
return 1;
return 1;
}
输出:
<Program>$.<<Main>$>g__H|0_2(Int32)
L0000: mov eax, 1
L0005: ret
问题
- 第二种情况为什么会生成额外的指令?
注释
- SharpLab链接,如果您想试玩一下。
- 这是使用
C
所生成的GCC(-O2)
:
int
f(int n) {
if (n == 1)
return 1;
return 1;
}
int
g(int n) {
if (n == 1)
return 1;
if (n == 1)
return 1;
return 1;
}
int
h(int n) {
if (n == 1)
return 1;
if (n == 1)
return 1;
if (n == 1)
return 1;
if (n == 1)
return 1;
if (n == 1)
return 1;
return 1;
}
生成如下内容:
f:
mov eax, 1
ret
g:
mov eax, 1
ret
h:
mov eax, 1
ret
这里是Godbolt链接。
- 函数的IL代码:
.method assembly hidebysig static
int32 '<<Main>$>g__F|0_0' (
int32 n
) cil managed
{
// Method begins at RVA 0x2052
// Code size 6 (0x6)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: pop
IL_0003: pop
IL_0004: ldc.i4.1
IL_0005: ret
} // end of method '<Program>$'::'<<Main>$>g__F|0_0'
.method assembly hidebysig static
int32 '<<Main>$>g__G|0_1' (
int32 n
) cil managed
{
// Method begins at RVA 0x2059
// Code size 12 (0xc)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: bne.un.s IL_0006
IL_0004: ldc.i4.1
IL_0005: ret
IL_0006: ldarg.0
IL_0007: ldc.i4.1
IL_0008: pop
IL_0009: pop
IL_000a: ldc.i4.1
IL_000b: ret
} // end of method '<Program>$'::'<<Main>$>g__G|0_1'
.method assembly hidebysig static
int32 '<<Main>$>g__H|0_2' (
int32 n
) cil managed
{
// Method begins at RVA 0x2066
// Code size 30 (0x1e)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: bne.un.s IL_0006
IL_0004: ldc.i4.1
IL_0005: ret
IL_0006: ldarg.0
IL_0007: ldc.i4.1
IL_0008: bne.un.s IL_000c
IL_000a: ldc.i4.1
IL_000b: ret
IL_000c: ldarg.0
IL_000d: ldc.i4.1
IL_000e: bne.un.s IL_0012
IL_0010: ldc.i4.1
IL_0011: ret
IL_0012: ldarg.0
IL_0013: ldc.i4.1
IL_0014: bne.un.s IL_0018
IL_0016: ldc.i4.1
IL_0017: ret
IL_0018: ldarg.0
IL_0019: ldc.i4.1
IL_001a: pop
IL_001b: pop
IL_001c: ldc.i4.1
IL_001d: ret
} // end of method '<Program>$'::'<<Main>$>g__H|0_2'