我的印象是这两个命令导致相同的结果,即将 X 增加 1,但后者可能更有效。
如果这不正确,请解释差异。
如果是正确的,为什么后者应该更有效率?他们不应该都编译成同一个IL吗?
谢谢。
我的印象是这两个命令导致相同的结果,即将 X 增加 1,但后者可能更有效。
如果这不正确,请解释差异。
如果是正确的,为什么后者应该更有效率?他们不应该都编译成同一个IL吗?
谢谢。
来自+= 的 MSDN 库:
使用此运算符与指定 result = result + expression 几乎相同,只是 result 只计算一次。
所以它们并不相同,这就是为什么 x += 1 会更有效。
更新:我刚刚注意到我的 MSDN Library 链接指向 JScript 页面而不是VB 页面,它不包含相同的引用。
因此,经过进一步的研究和测试,该答案不适用于 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
}
PlusEqual2 和 Add2 的 IL 也几乎相同:
.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
}
我写了一个简单的控制台应用程序:
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);
}
他们是一样的。
它们编译成相同的,第二个更容易输入。
+=
在一般语言中,指定评估的答案在做什么方面肯定是正确的。但是在 VB.NET 中,我假设X
在 OP 中指定的是一个变量或一个属性。
它们可能会编译为相同的 IL。
VB.NET 是一种编程语言规范。任何符合规范中定义的编译器都可以是 VB.NET 实现。如果您编辑 MS VB.NET 编译器的源代码以生成用于X += 1
案例的蹩脚代码,您仍然会符合 VB.NET 规范(因为它没有说明它将如何工作。它只是说明了效果将完全相同,这使得生成相同的代码是合乎逻辑的,确实)。
虽然编译器很可能(我觉得确实如此)为两者生成相同的代码,但它是一个相当复杂的软件。哎呀,当相同的代码被编译两次时,你甚至不能保证编译器生成完全相同的代码!
您可以 100% 确定地说(除非您非常了解编译器的源代码)是一个好的编译器应该生成相同的代码,性能方面,这可能是也可能不是完全相同的代码。
这么多猜测!即使是反射器的结论也不一定正确,因为它可以在拆卸时进行优化。
那么为什么你们没有人只看一下 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 中是一样的
在 x86 上,如果 x 在寄存器 eax 中,它们都会导致类似
公司;
所以你是对的,经过一些编译阶段,IL 将是相同的。
有一整类这样的问题可以用“相信你的优化器”来回答。
著名的神话是
x++;
效率低于
++x;
因为它必须存储一个临时值。如果您从不使用临时值,优化器将删除该存储。
它们在 VB 中可能相同;它们在 C 中不一定相同(运算符来自哪里)。
如果 x 是像 int 或 float 这样的简单类型,优化器可能会产生相同的结果。
如果您使用其他语言(此处的 VB 知识有限,您可以重载 += 吗?)其中 x 可能是一个大喇叭对象,前者会创建和额外的副本,可能是数百兆。后者没有。
是相同的。
x=x+1
数学被认为是矛盾的,而
x+=1
不是而且很容易打字。
在 C++ 中,它取决于x是什么数据类型以及如何定义运算符。如果x是某个类的实例,您可以获得完全不同的结果。
或者也许你应该解决这个问题并指定x是一个整数或其他什么。
我认为差异是由于用于内存引用的额外时钟周期,但结果我错了!我自己无法理解这件事
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它只是一些可能有用的数据。请给出意见!
值得注意的是 +=、-=、*= 等进行了隐式转换。
int i = 0;
i = i + 5.5; // doesn't compile.
i += 5.5; // compiles.
在运行时(至少使用 PERL)没有区别。x+=1 比 x = x+1 快大约 0.5 秒
程序效率没有区别;只是打字效率。
早在 1980 年代初期,Lattice C 编译器的一项非常酷的优化就是“x = x + 1;”、“x += 1;” 和“x++;” 都产生了完全相同的机器代码。如果他们可以做到,那么这个千年编写的编译器肯定可以做到。
如果 x 是一个简单的整数标量变量,它们应该是相同的。
如果 x 是一个大表达式,可能有副作用,+=1
并且++
应该快两倍。
许多人专注于这种低级优化,好像这就是优化的全部内容。我假设你知道这是一个更大的主题。