х = х + 1 против х + = 1 - PullRequest
       42

х = х + 1 против х + = 1

29 голосов
/ 30 апреля 2009

У меня сложилось впечатление, что эти две команды приводят к одному и тому же концу, а именно увеличивают X на 1, но последнее, вероятно, более эффективно.

Если это не правильно, объясните разницу.

Если это правильно, почему последний должен быть более эффективным? Разве они не должны компилироваться в один и тот же IL?

Спасибо.

Ответы [ 17 ]

106 голосов
/ 30 апреля 2009

Из библиотеки MSDN для + = :

Использование этого оператора практически совпадает с указанием result = result + expression, за исключением того, что результат оценивается только один раз.

Так что они не идентичны, и поэтому x + = 1 будет более эффективным.

Обновление: Я только что заметил, что моя ссылка на библиотеку MSDN была на страницу 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

IL для PlusEqual1 и Add1 действительно идентичны:

.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 для 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 
}
25 голосов
/ 30 апреля 2009

Я написал простое консольное приложение:

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);
}

Они одинаковы.

18 голосов
/ 30 апреля 2009

они компилируются одинаково, второй просто набрать.

11 голосов
/ 30 апреля 2009

ВАЖНО:

Ответы, определяющие оценку, безусловно, правильны с точки зрения того, что делает +=, на общих языках. Но в VB.NET я предполагаю, что X, указанное в OP, является переменной или свойством.


Они, вероятно, будут компилироваться в один и тот же IL.

ОБНОВЛЕНИЕ (для устранения вероятного противоречия):

VB.NET - это спецификация языка программирования. Любой компилятор, который соответствует тому, что определено в спецификации, может быть реализацией VB.NET. Если вы отредактируете исходный код компилятора MS VB.NET, чтобы сгенерировать дрянной код для случая X += 1, вы все равно будете соответствовать спецификации VB.NET (поскольку в ней ничего не сказано о том, как она будет работать. Это просто говорит, что эффект будет точно таким же, что логично генерировать тот же код, действительно).

Хотя компилятор очень и очень вероятно (и я чувствую, что это действительно так) генерирует один и тот же код для обоих, но это довольно сложная часть программного обеспечения. Черт возьми, вы даже не можете гарантировать, что компилятор генерирует точно такой же код, когда один и тот же код компилируется дважды!

Что вы можете сказать на 100% безопасно (если вы не знаете исходный код компилятора), это то, что хороший компилятор должен генерировать такой же код с точки зрения производительности , который может или не может быть быть точно таким же кодом .

8 голосов
/ 30 апреля 2009

Так много спекуляций! Даже вывод с отражателем не обязательно верен, потому что он может выполнять оптимизацию при разборке.

Так почему никто из вас, ребята, просто не взглянул на код 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

4 голосов
/ 30 апреля 2009

На x86, если x находится в регистре eax, они оба приведут к чему-то вроде

inc eax;

Итак, вы правы, после некоторой стадии компиляции IL будет таким же.

Существует целый ряд подобных вопросов, на которые можно ответить «доверься оптимизатору».

Знаменитый миф о том, что
х ++;
менее эффективен, чем
++ х;
потому что он должен хранить временное значение. Если вы никогда не используете временное значение, оптимизатор удалит это хранилище.

2 голосов
/ 30 апреля 2009

Они могут быть одинаковыми в VB; они не обязательно одинаковы в C (откуда происходит оператор).

2 голосов
/ 30 апреля 2009
  1. Да, они ведут себя одинаково.
  2. Нет, они, вероятно, одинаково эффективны. Оптимизаторы хороши в таких вещах. Если вы хотите перепроверить, напишите оптимизированный код и просмотрите его в отражателе.
2 голосов
/ 30 апреля 2009

Оптимизатор, вероятно, выдаст тот же результат, если x - простой тип, такой как int или float.

Если бы вы использовали какой-то другой язык (здесь ограниченное знание VB, можете ли вы перегружать + =?), Где x мог бы быть одним большим сигналяющим объектом, первый создает и дополнительную копию, которая может быть сотнями мегабайт. Последнее не.

2 голосов
/ 30 апреля 2009

одинаковы.

x=x+1 

математически видел противоречие, тогда как

x+=1

не так и легко печатать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...