📜 ⬆️ ⬇️

Increment in c # inside

Published at the request of Rextor, which has no account on the swag.
Write this post made me a discussion in the post insidious question on Event \ Delegate ()
increment sequence values ​​(which is better than i ++ or, ++ i), and whether it has a fundamental importance (the number of generated objects and execution cycles).
Immediately I warn you that I am writing about separately-standing increments, not method call arguments.
Construction Method (++ i); Of course, it will always be better than i ++; Method (i);

In order to find out, a simple application was created that checks this, which was compiled as a release (so that the compiler does not add extra breakpoints) and was disassembled by the Reflector Reflector .
Due to the fact that there are only 2 main types in .net of which all the rest are created (ValueType and Object), 2 types were selected for consideration: Int32 and a class with an increment overload. I dare to assume that the behavior of all other types and methods of overload should be the same.
And so the listing of the application itself:

The class of the main method:

class Program{
static void Main( string [] args){
Console .WriteLine ( " " );
int i = 0;
int j = 0;
i++;
++j;
Console .WriteLine(i);
Console .WriteLine(j);
Console .WriteLine(i++);
//
Console .WriteLine(i);
Console .WriteLine(++j);

SampleClass class_i= new SampleClass();
SampleClass class_j = new SampleClass();

class_i++;
++class_j;
Console .WriteLine(class_i);
Console .WriteLine(class_j);

Console .WriteLine(class_i++);
//
Console .WriteLine(class_i);
Console .WriteLine(++class_j);

Console .ReadLine();

}
}

* This source code was highlighted with Source Code Highlighter .

Class with increment overload:
class SampleClass{
public SampleClass() {
num = 0;
}
int num;
// ++
public static SampleClass operator ++(SampleClass a){
return new SampleClass() {num=++a.num};
}
public override string ToString(){
return num.ToString();
}
}

* This source code was highlighted with Source Code Highlighter .

The cleaned-up program was sent to the mercy of Reflector (it was possible, of course, to skip over ILDasm, but I find it not convenient to work with it).
The code described below was obtained from Reflector (a link to the full source file is given at the end of the post):
')
The first line indicates that this method is used to enter the application:

.entrypoint

Specify the size used in the stack method:
.maxstack 3

And the declaration of all variables
.locals init (
[0] int32 i,
[1] int32 j,
[2] class SampleClass class_i, //
[3] class SampleClass class_j
)

The following line loads and displays the text: “Almost without useful text output” , the reason for this output will be disclosed just below.
L_0000: ldstr "\u0411\u0435\u0437\u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442"
L_0005: call void [mscorlib]System. Console ::WriteLine( string )

Next, the text of the method itself begins, the first part of which performs operations with an intent:

Zeroing the values ​​of variables
//i=0
L_000a: ldc.i4.0 // 0
L_000b: stloc.0 // i

//j=0;
L_000c: ldc.i4.0 // 0
L_000d: stloc.1 // j

Here are our increments
//i++
L_000e: ldloc.0 // i
L_000f: ldc.i4.1 // 1
L_0010: add //
L_0011: stloc.0 // i

//++j
L_0012: ldloc.1 //
L_0013: ldc.i4.1
L_0014: add
L_0015: stloc.1

* This source code was highlighted with Source Code Highlighter .

As can be seen from the previous section of the code, the increment of both variables in this case is the same

The following code section prints the values ​​of the variables to the console:

// i j
L_0016: ldloc.0 //
L_0017: call void [mscorlib]System. Console ::WriteLine(int32)
L_001c: ldloc.1
L_001d: call void [mscorlib]System. Console ::WriteLine(int32)

The first difference appears further, with increment right at the time of output to the console (I lied a little when I wrote at the beginning that this case would not be considered)
L_0022: ldloc.0 // i
L_0023: dup //
L_0024: ldc.i4.1 // 1
L_0025: add // 2
L_0026: stloc.0 // i

L_0027: call void [mscorlib]System. Console ::WriteLine(int32) //

// i (024-026)
L_002c: ldloc.0
L_002d: call void [mscorlib]System. Console ::WriteLine(int32)

// j++ ( i )
L_0032: ldloc.1
L_0033: ldc.i4.1
L_0034: add
L_0035: dup // , 22-27
L_0036: stloc.1
L_0037: call void [mscorlib]System. Console ::WriteLine(int32)

* This source code was highlighted with Source Code Highlighter .

Next comes the part of the method that performs the same with the classes (to be honest, I could not even imagine that the code would be so similar)
// SampleClass (class_i)
L_003c: newobj instance void SampleClass::.ctor()
L_0041: stloc.2

// SampleClass (class_j)
L_0042: newobj instance void SampleClass::.ctor()
L_0047: stloc.3

// class_i ++
L_0048: ldloc.2
L_0049: call class SampleClass SampleClass::op_Increment( class SampleClass)
L_004e: stloc.2

// class_j
L_004f: ldloc.3
L_0050: call class SampleClass SampleClass::op_Increment( class SampleClass)
L_0055: stloc.3

// class_i
L_0056: ldloc.2
L_0057: call void [mscorlib]System. Console ::WriteLine( object )

// class_j
L_005c: ldloc.3
L_005d: call void [mscorlib]System. Console ::WriteLine( object )

// class_i ,
L_0062: ldloc.2
L_0063: dup
L_0064: call class SampleClass SampleClass::op_Increment( class SampleClass)
L_0069: stloc.2

//
L_006a: call void [mscorlib]System. Console ::WriteLine( object )
L_006f: ldloc.2
// , , L_0063: dup
L_0070: call void [mscorlib]System. Console ::WriteLine( object )

// class_j ,
L_0075: ldloc.3
L_0076: call class SampleClass SampleClass::op_Increment( class SampleClass)
L_007b: dup
L_007c: stloc.3
L_007d: call void [mscorlib]System. Console ::WriteLine( object )

// "Pres any Key to Contune.. ;)"
L_0082: call string [mscorlib]System. Console ::ReadLine()
L_0087: pop //
L_0088: ret //

* This source code was highlighted with Source Code Highlighter .

And now, as promised, I will reveal the reason for why there was a first line of text to the console. The fact is that I decided to check whether there were any differences after compiling the program (into pure machine instructions), but since the initialization code of the method and the declaration merged, I had to insert a line separating the method and initialization code.
So, as a result of the comparison, it turned out that the code on a pure asm is also almost the same:
When working with Integers, the code blocks copying the value to the stack, producing an addition of units and saving back were replaced with one Inc operator.
In the case of a class increment, the order of the call changes (as in the IL code)
By the way, the source code for asma is also given below. For those who wish to delve into them, you are welcome:

IL code

Assembly code

Archived project

Source: https://habr.com/ru/post/66167/


All Articles