我在玩 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 链接,如果你想玩的话。
- 这是
GCC (-O2)
使用C
生成的:
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'