我的印象是这两个命令导致相同的结果,即将X递增1,但后者可能更有效。
如果这不正确,请解释差异。
如果它是正确的,为什么后者会更有效率?他们不应该编译到同一个IL吗?
感谢。
答案 0 :(得分:106)
使用此运算符与指定result = result + expression几乎相同,只是结果只计算一次。
所以它们不相同,这就是x + = 1效率更高的原因。
更新:我刚刚注意到我的MSDN Library链接是JScript页面而不是VB page,它不包含相同的引用。
因此,经过进一步的研究和测试,该答案不适用于VB.NET。我错了。这是一个示例控制台应用程序:
Module Module1
Sub Main()
Dim x = 0
Console.WriteLine(PlusEqual1(x))
Console.WriteLine(Add1(x))
Console.WriteLine(PlusEqual2(x))
Console.WriteLine(Add2(x))
Console.ReadLine()
End Sub
Public Function PlusEqual1(ByVal x As Integer) As Integer
x += 1
Return x
End Function
Public Function Add1(ByVal x As Integer) As Integer
x = x + 1
Return x
End Function
Public Function PlusEqual2(ByVal x As Integer) As Integer
x += 2
Return x
End Function
Public Function Add2(ByVal x As Integer) As Integer
x = x + 2
Return x
End Function
End Module
PlusEqual1和Add1的IL确实相同:
.method public static int32 Add1(int32 x) cil managed
{
.maxstack 2
.locals init (
[0] int32 Add1)
L_0000: nop
L_0001: ldarg.0
L_0002: ldc.i4.1
L_0003: add.ovf
L_0004: starg.s x
L_0006: ldarg.0
L_0007: stloc.0
L_0008: br.s L_000a
L_000a: ldloc.0
L_000b: ret
}
IL for PlusEqual2和Add2几乎完全相同:
.method public static int32 Add2(int32 x) cil managed
{
.maxstack 2
.locals init (
[0] int32 Add2)
L_0000: nop
L_0001: ldarg.0
L_0002: ldc.i4.2
L_0003: add.ovf
L_0004: starg.s x
L_0006: ldarg.0
L_0007: stloc.0
L_0008: br.s L_000a
L_000a: ldloc.0
L_000b: ret
}
答案 1 :(得分:25)
我写了一个简单的控制台应用程序:
static void Main(string[] args)
{
int i = 0;
i += 1;
i = i + 1;
Console.WriteLine(i);
}
我使用Reflector对它进行了反汇编,这就是我得到的:
private static void Main(string[] args)
{
int i = 0;
i++;
i++;
Console.WriteLine(i);
}
他们是一样的。
答案 2 :(得分:18)
他们编译成相同的,第二个更容易输入。
答案 3 :(得分:11)
在一般语言中,指定评估的答案在+=
所做的事情方面肯定是正确的。但是在VB.NET中,我假设OP中指定的X
是变量或属性。
他们可能会编译到同一个IL。
VB.NET是一种编程语言的规范。任何符合规范中定义的编译器都可以是VB.NET实现。如果您编辑MS VB.NET编译器的源代码以生成X += 1
案例的糟糕代码,您仍将符合VB.NET规范(因为它没有说明它将如何工作。它只是说效果将完全相同,这使得生成相同的代码确实合乎逻辑。
虽然编译器很可能(我觉得它确实如此)为两者生成相同的代码,但它是相当复杂的软件。哎呀,你甚至不能保证编译器在编译两次相同的代码时生成完全相同的代码!
你可以100%安全地说(除非你知道编译器的源代码)是一个好的编译器应该生成相同的代码,性能方面,这可能或可能不是完全相同的代码。
答案 4 :(得分:8)
这么多猜测!即使是使用Reflector thingy的结论也不一定正确,因为它可以在反汇编时进行优化。
那么为什么你们这些人都没看过IL代码?看看下面的C#程序:
static void Main(string[] args)
{
int x = 2;
int y = 3;
x += 1;
y = y + 1;
Console.WriteLine(x);
Console.WriteLine(y);
}
此代码段编译为:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] int32 x,
[1] int32 y)
// some commands omitted here
IL_0004: ldloc.0
IL_0005: ldc.i4.1
IL_0006: add
IL_0007: stloc.0
IL_0008: ldloc.1
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stloc.1
// some commands omitted here
}
正如您所看到的,它实际上完全相同。为什么呢?因为IL的目的是告诉做什么,而不是如何做。优化将是JIT编译器的工作。顺便说一句,它在VB.Net中是一样的
答案 5 :(得分:4)
在x86上,如果x在寄存器eax中,它们都会产生类似
的内容 inc eax;
所以你是对的,在一些编译阶段之后,IL将是相同的。
这类问题可以用“信任你的优化者”来回答。
着名的神话是
X ++;
效率低于
++ X;
因为它必须存储一个临时值。如果您从不使用临时值,优化程序将删除该存储。
答案 6 :(得分:2)
是一样的。
x=x+1
是数学上的矛盾,而
x+=1
不是,而且打字很轻。
答案 7 :(得分:2)
如果x是一个简单的类型,如int或float。
,优化器可能会产生相同的结果如果你使用其他语言(这里有限的VB知识,你可以重载+ =?),其中x可能是一个大的鸣笛对象,前者创建和额外的副本,可以是数百兆。后者没有。
答案 8 :(得分:2)
答案 9 :(得分:2)
它们在VB中可能是相同的;它们在C中并不一定相同(操作员来自)。
答案 10 :(得分:1)
在C ++中,它取决于 x 的数据类型以及如何定义运算符。如果 x 是某个类的实例,则可以获得完全不同的结果。
或许您应该解决问题并指定 x 是整数或其他。
答案 11 :(得分:1)
我认为差异是由于用于内存引用的额外时钟周期,但我结果证明是错误的!我自己无法理解这件事
instruction type example cycles
=============================================== ====================
ADD reg,reg add ax,bx 1
ADD mem,reg add total, cx 3
ADD reg,mem add cx,incr 2
ADD reg,immed add bx,6 1
ADD mem,immed add pointers[bx][si],6 3
ADD accum,immed add ax,10 1
INC reg inc bx 1
INC mem inc vpage 3
MOV reg,reg mov bp,sp 1
MOV mem,reg mov array[di],bx 1
MOV reg,mem mov bx,pointer 1
MOV mem,immed mov [bx],15 1
MOV reg,immed mov cx,256 1
MOV mem,accum mov total,ax 1
MOV accum,mem mov al,string 1
MOV segreg,reg16 mov ds,ax 2, 3
MOV segreg,mem16 mov es,psp 2, 3
MOV reg16,segreg mov ax,ds 1
MOV mem16,segreg mov stack_save,ss 1
MOV reg32,controlreg mov eax,cr0 22
mov eax,cr2 12
mov eax,cr3 21, 46
mov eax,cr4 14
MOV controlreg,reg32 mov cr0,eax 4
MOV reg32,debugreg mov edx,dr0 DR0-DR3,DR6,DR7=11;
DR4,DR5=12
MOV debugreg,reg32 mov dr0,ecx DR0-DR3,DR6,DR7=11;
DR4,DR5=12
源:http://turkish_rational.tripod.com/trdos/pentium.txt
指令可以翻译为:
;for i = i+1 ; cycles
mov ax, [i] ; 1
add ax, 1 ; 1
mov [i], ax ; 1
;for i += 1
; dunno the syntax of instruction. it should be the pointers one :S
;for i++
inc i ; 3
;or
mov ax, [i] ; 1
inc ax ; 1
mov [i], ax ; 1
;for ++i
mov ax, [i] ; 1
;do stuff ; matters not
inc ax ; 1
mov [i], ax ; 1
结果都是一样的:S
它只是一些可能有用的数据。请评论!
答案 12 :(得分:1)
值得注意的是+ =, - =,* =等进行隐式演员。
int i = 0;
i = i + 5.5; // doesn't compile.
i += 5.5; // compiles.
答案 13 :(得分:0)
程序效率没有区别;只是输入效率。
答案 14 :(得分:0)
早在20世纪80年代初,莱迪思C编译器的一个非常酷的优化是“x = x + 1;”,“x + = 1;”和“x ++;”所有产生完全相同的机器代码。如果他们能够做到这一点,那么千禧年编写的编译器肯定能够做到。
答案 15 :(得分:0)
在运行时(至少使用PERL)没有区别。 x + = 1大约比x = x + 1快0.5秒,但是
答案 16 :(得分:0)
如果x是一个简单的整数标量变量,它们应该是相同的。
如果x是一个大表达式,可能带有副作用,+=1
和++
应该快两倍。
许多人专注于这种低级优化,就好像这就是优化的全部内容。我猜你知道这是一个更大的主题。